@altano/astro-opengraph 0.1.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { OpengraphImageConfigDeserialized, OpengraphImageConfigResolved, OpengraphImageConfigSerializableMaybeMocked } from "./types-B1hoqgLx.js";
1
+ import { OpengraphImageConfigDeserialized, OpengraphImageConfigResolved, OpengraphImageConfigSerializableMaybeMocked } from "./types-BGbFKpbi.js";
2
2
 
3
3
  //#region src/config.d.ts
4
4
  declare function deserializeVirtualConfig(configMaybeMocked: OpengraphImageConfigSerializableMaybeMocked): Promise<OpengraphImageConfigDeserialized>;
package/dist/config.js CHANGED
@@ -1,3 +1,43 @@
1
- import { deserializeVirtualConfig, getResolvedConfig } from "./config-CzK0JuaO.js";
1
+ import { readFile } from "node:fs/promises";
2
+ //#region src/config.ts
3
+ async function deserializeVirtualConfig(configMaybeMocked) {
4
+ const config = typeof configMaybeMocked === "function" ? configMaybeMocked() : configMaybeMocked;
5
+ const fontsWithBuffers = await Promise.all(config.imageOptions.fonts.map(async (font) => {
6
+ const data = await readFile(font.path);
7
+ return {
8
+ ...font,
9
+ data
10
+ };
11
+ }));
12
+ return {
13
+ ...config,
14
+ imageOptions: {
15
+ ...config.imageOptions,
16
+ fonts: fontsWithBuffers
17
+ }
18
+ };
19
+ }
20
+ const imageOptionDefaults = {
21
+ width: 1200,
22
+ height: 630
23
+ };
24
+ const metaTagDefaults = { "og:image": `/opengraph.png` };
25
+ async function getResolvedConfig() {
26
+ const lazyConfig = (await import("virtual:astro-opengraph/user-config")).default;
27
+ const deserialized = await deserializeVirtualConfig(lazyConfig);
28
+ return {
29
+ ...deserialized,
30
+ imageOptions: {
31
+ ...imageOptionDefaults,
32
+ ...deserialized.imageOptions
33
+ },
34
+ componentMetaTagFallbacks: {
35
+ ...deserialized.componentMetaTagFallbacks,
36
+ ...metaTagDefaults
37
+ }
38
+ };
39
+ }
40
+ //#endregion
41
+ export { deserializeVirtualConfig, getResolvedConfig };
2
42
 
3
- export { deserializeVirtualConfig, getResolvedConfig };
43
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\n\nimport type {\n FontWithBuffer,\n MetaTagDefaults,\n OpengraphImageConfigDeserialized,\n OpengraphImageConfigResolved,\n OpengraphImageConfigSerializableMaybeMocked,\n} from \"./types.js\";\n\nexport async function deserializeVirtualConfig(\n configMaybeMocked: OpengraphImageConfigSerializableMaybeMocked,\n): Promise<OpengraphImageConfigDeserialized> {\n const config =\n typeof configMaybeMocked === \"function\"\n ? configMaybeMocked() // We're running in vitest which is only capable of mocking functions\n : configMaybeMocked;\n const fontsWithBuffers: FontWithBuffer[] = await Promise.all(\n config.imageOptions.fonts.map(async (font) => {\n const data = await readFile(font.path);\n return {\n ...font,\n data: data,\n };\n }),\n );\n\n return {\n ...config,\n imageOptions: {\n ...config.imageOptions,\n fonts: fontsWithBuffers,\n },\n };\n}\n\nconst imageOptionDefaults = {\n width: 1200,\n height: 630,\n} as const;\n\nconst metaTagDefaults: MetaTagDefaults = {\n \"og:image\": `/opengraph.png`,\n};\n\nexport async function getResolvedConfig(): Promise<OpengraphImageConfigResolved> {\n // Grab the virtual module that holds the integration's user config\n const module = await import(\"virtual:astro-opengraph/user-config\");\n const lazyConfig = module.default;\n const deserialized = await deserializeVirtualConfig(lazyConfig);\n return {\n ...deserialized,\n imageOptions: {\n ...imageOptionDefaults,\n ...deserialized.imageOptions,\n },\n componentMetaTagFallbacks: {\n ...deserialized.componentMetaTagFallbacks,\n ...metaTagDefaults,\n },\n };\n}\n"],"mappings":";;AAUA,eAAsB,yBACpB,mBAC2C;CAC3C,MAAM,SACJ,OAAO,sBAAsB,aACzB,mBAAmB,GACnB;CACN,MAAM,mBAAqC,MAAM,QAAQ,IACvD,OAAO,aAAa,MAAM,IAAI,OAAO,SAAS;EAC5C,MAAM,OAAO,MAAM,SAAS,KAAK,KAAK;AACtC,SAAO;GACL,GAAG;GACG;GACP;GACD,CACH;AAED,QAAO;EACL,GAAG;EACH,cAAc;GACZ,GAAG,OAAO;GACV,OAAO;GACR;EACF;;AAGH,MAAM,sBAAsB;CAC1B,OAAO;CACP,QAAQ;CACT;AAED,MAAM,kBAAmC,EACvC,YAAY,kBACb;AAED,eAAsB,oBAA2D;CAG/E,MAAM,cADS,MAAM,OAAO,wCACF;CAC1B,MAAM,eAAe,MAAM,yBAAyB,WAAW;AAC/D,QAAO;EACL,GAAG;EACH,cAAc;GACZ,GAAG;GACH,GAAG,aAAa;GACjB;EACD,2BAA2B;GACzB,GAAG,aAAa;GAChB,GAAG;GACJ;EACF"}
@@ -1,11 +1,13 @@
1
- import { ImageOptions } from "./types-B1hoqgLx.js";
1
+ import { ImageOptions } from "./types-BGbFKpbi.js";
2
2
  import { APIRoute } from "astro";
3
3
 
4
4
  //#region src/endpoint.d.ts
5
5
  type Options = {
6
- // We don't just type this as `AstroComponentFactory` because astro typing is
7
- // hard to get right and simply importing a .astro file doesn't give you
8
- // something typed as a factory.
6
+ /**
7
+ * We don't just type this as `AstroComponentFactory` because astro typing is
8
+ * hard to get right and simply importing a .astro file doesn't give you
9
+ * something typed as a factory.
10
+ */
9
11
  template: unknown;
10
12
  /**
11
13
  * Custom "Content-Type" header, only used in SSR. Defaults to "image/png"
package/dist/endpoint.js CHANGED
@@ -1,43 +1,35 @@
1
- import { getResolvedConfig } from "./config-CzK0JuaO.js";
1
+ import { getResolvedConfig } from "./config.js";
2
2
  import { experimental_AstroContainer } from "astro/container";
3
3
  import { isAstroComponentFactory } from "astro/runtime/server/render/astro/factory.js";
4
4
  import { getConfiguredImageService, imageConfig } from "astro:assets";
5
5
  import satori from "satori";
6
6
  import { html } from "satori-html";
7
7
  import he from "he";
8
-
9
8
  //#region src/image.ts
10
9
  /**
11
10
  * Convert an html string to an image
12
11
  */
13
12
  async function htmlToPNG(html$1, satoriOptions) {
14
- const responseTextWithDecodedHtmlEntities = he.decode(html$1);
15
- const vnode = html(responseTextWithDecodedHtmlEntities);
16
- const svg = await satori(vnode, satoriOptions);
13
+ const svg = await satori(html(he.decode(html$1)), satoriOptions);
17
14
  const fileBuffer = Buffer.from(svg, "utf-8");
18
- const uint8Array = new Uint8Array(fileBuffer.buffer, fileBuffer.byteOffset, fileBuffer.byteLength);
19
- return bufferToTransformedPNG(uint8Array);
15
+ return bufferToTransformedPNG(new Uint8Array(fileBuffer.buffer, fileBuffer.byteOffset, fileBuffer.byteLength));
20
16
  }
21
17
  /**
22
18
  * Convert a buffer to an image using the astro local image service
23
19
  */
24
20
  async function bufferToTransformedPNG(imageBuffer) {
25
- const imageService = await getConfiguredImageService();
26
- return imageService.transform(imageBuffer, {
21
+ return (await getConfiguredImageService()).transform(imageBuffer, {
27
22
  src: "",
28
23
  format: "png"
29
24
  }, imageConfig);
30
25
  }
31
-
32
26
  //#endregion
33
27
  //#region src/endpoint.ts
34
28
  function makeOpengraphDevEndpoint({ template, contentType = "text/html" }) {
35
29
  return async ({ locals, params, props, request }) => {
36
- const config = await getResolvedConfig();
37
- if (config.command !== "dev") return new Response(null, { status: 404 });
30
+ if ((await getResolvedConfig()).command !== "dev") return new Response(null, { status: 404 });
38
31
  if (!isAstroComponentFactory(template)) throw new Error(`Given is not an Astro template.`);
39
- const container = await experimental_AstroContainer.create();
40
- const templateStr = await container.renderToString(template, {
32
+ const templateStr = await (await experimental_AstroContainer.create()).renderToString(template, {
41
33
  partial: false,
42
34
  request,
43
35
  params,
@@ -50,24 +42,20 @@ function makeOpengraphDevEndpoint({ template, contentType = "text/html" }) {
50
42
  function makeOpengraphEndpoint({ template, imageOptionOverrides, contentType = "image/png" }) {
51
43
  return async ({ locals, params, props, request }) => {
52
44
  if (!isAstroComponentFactory(template)) throw new Error(`Given is not an Astro template.`);
53
- const container = await experimental_AstroContainer.create();
54
- const templateStr = await container.renderToString(template, {
45
+ const png = await htmlToPNG(await (await experimental_AstroContainer.create()).renderToString(template, {
55
46
  partial: false,
56
47
  request,
57
48
  params,
58
49
  locals,
59
50
  props
60
- });
61
- const config = await getResolvedConfig();
62
- const imageOptions = {
63
- ...config.imageOptions,
51
+ }), {
52
+ ...(await getResolvedConfig()).imageOptions,
64
53
  ...imageOptionOverrides
65
- };
66
- const png = await htmlToPNG(templateStr, imageOptions);
67
- return new Response(png.data, { headers: { "Content-Type": contentType } });
54
+ });
55
+ return new Response(new Uint8Array(png.data), { headers: { "Content-Type": contentType } });
68
56
  };
69
57
  }
70
-
71
58
  //#endregion
72
59
  export { makeOpengraphDevEndpoint, makeOpengraphEndpoint };
60
+
73
61
  //# sourceMappingURL=endpoint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint.js","names":["html: string","satoriOptions: SatoriOptions","html","imageBuffer: Uint8Array"],"sources":["../src/image.ts","../src/endpoint.ts"],"sourcesContent":["import { getConfiguredImageService, imageConfig } from \"astro:assets\";\nimport satori, { type SatoriOptions } from \"satori\";\nimport { html as htmlToVNode } from \"satori-html\";\nimport he from \"he\";\n\nimport type { LocalImageService } from \"astro\";\n\n/**\n * Convert an html string to an image\n */\nexport async function htmlToPNG(\n html: string,\n satoriOptions: SatoriOptions,\n): Promise<ReturnType<LocalImageService[\"transform\"]>> {\n // html text => vnode\n const responseTextWithDecodedHtmlEntities = he.decode(html);\n const vnode = htmlToVNode(responseTextWithDecodedHtmlEntities);\n\n // vnode => svg\n const svg = await satori(vnode as React.ReactNode, satoriOptions);\n\n // svg => buffer\n const fileBuffer = Buffer.from(svg, \"utf-8\");\n const uint8Array = new Uint8Array(\n fileBuffer.buffer,\n fileBuffer.byteOffset,\n fileBuffer.byteLength,\n );\n\n // buffer => transformed png\n return bufferToTransformedPNG(uint8Array);\n}\n\n/**\n * Convert a buffer to an image using the astro local image service\n */\nasync function bufferToTransformedPNG(\n imageBuffer: Uint8Array,\n): ReturnType<LocalImageService[\"transform\"]> {\n const imageService = (await getConfiguredImageService()) as LocalImageService;\n\n return imageService.transform(\n imageBuffer,\n { src: \"\", format: \"png\" },\n imageConfig,\n );\n}\n","import type { APIRoute } from \"astro\";\nimport { experimental_AstroContainer } from \"astro/container\";\nimport { isAstroComponentFactory } from \"astro/runtime/server/render/astro/factory.js\";\nimport { getResolvedConfig } from \"./config.js\";\nimport type { ImageOptions } from \"./types.js\";\nimport { htmlToPNG } from \"./image.js\";\n\ntype Options = {\n // We don't just type this as `AstroComponentFactory` because astro typing is\n // hard to get right and simply importing a .astro file doesn't give you\n // something typed as a factory.\n template: unknown;\n /**\n * Custom \"Content-Type\" header, only used in SSR. Defaults to \"image/png\"\n */\n contentType?: string;\n imageOptionOverrides?: Partial<ImageOptions>;\n};\n\nexport function makeOpengraphDevEndpoint({\n template,\n contentType = \"text/html\",\n}: Options): APIRoute {\n return async ({ locals, params, props, request }) => {\n const config = await getResolvedConfig();\n if (config.command !== \"dev\") {\n return new Response(null, { status: 404 });\n }\n\n if (!isAstroComponentFactory(template)) {\n throw new Error(`Given is not an Astro template.`);\n }\n\n const container = await experimental_AstroContainer.create();\n const templateStr = await container.renderToString(template, {\n partial: false,\n request,\n params,\n locals,\n props,\n });\n\n return new Response(templateStr, {\n headers: {\n \"Content-Type\": contentType,\n },\n });\n };\n}\n\nexport function makeOpengraphEndpoint({\n template,\n imageOptionOverrides,\n contentType = \"image/png\",\n}: Options): APIRoute {\n return async ({ locals, params, props, request }) => {\n if (!isAstroComponentFactory(template)) {\n throw new Error(`Given is not an Astro template.`);\n }\n\n const container = await experimental_AstroContainer.create();\n const templateStr = await container.renderToString(template, {\n partial: false,\n request,\n params,\n locals,\n props,\n });\n\n const config = await getResolvedConfig();\n const imageOptions = {\n ...config.imageOptions,\n ...imageOptionOverrides,\n };\n const png = await htmlToPNG(templateStr, imageOptions);\n\n return new Response(png.data, {\n headers: {\n \"Content-Type\": contentType,\n },\n });\n };\n}\n"],"mappings":";;;;;;;;;;;;AAUA,eAAsB,UACpBA,QACAC,eACqD;CAErD,MAAM,sCAAsC,GAAG,OAAOC,OAAK;CAC3D,MAAM,QAAQ,KAAY,oCAAoC;CAG9D,MAAM,MAAM,MAAM,OAAO,OAA0B,cAAc;CAGjE,MAAM,aAAa,OAAO,KAAK,KAAK,QAAQ;CAC5C,MAAM,aAAa,IAAI,WACrB,WAAW,QACX,WAAW,YACX,WAAW;AAIb,QAAO,uBAAuB,WAAW;AAC1C;;;;AAKD,eAAe,uBACbC,aAC4C;CAC5C,MAAM,eAAgB,MAAM,2BAA2B;AAEvD,QAAO,aAAa,UAClB,aACA;EAAE,KAAK;EAAI,QAAQ;CAAO,GAC1B,YACD;AACF;;;;AC3BD,SAAgB,yBAAyB,EACvC,UACA,cAAc,aACN,EAAY;AACpB,QAAO,OAAO,EAAE,QAAQ,QAAQ,OAAO,SAAS,KAAK;EACnD,MAAM,SAAS,MAAM,mBAAmB;AACxC,MAAI,OAAO,YAAY,MACrB,QAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAK;AAG3C,OAAK,wBAAwB,SAAS,CACpC,OAAM,IAAI,OAAO;EAGnB,MAAM,YAAY,MAAM,4BAA4B,QAAQ;EAC5D,MAAM,cAAc,MAAM,UAAU,eAAe,UAAU;GAC3D,SAAS;GACT;GACA;GACA;GACA;EACD,EAAC;AAEF,SAAO,IAAI,SAAS,aAAa,EAC/B,SAAS,EACP,gBAAgB,YACjB,EACF;CACF;AACF;AAED,SAAgB,sBAAsB,EACpC,UACA,sBACA,cAAc,aACN,EAAY;AACpB,QAAO,OAAO,EAAE,QAAQ,QAAQ,OAAO,SAAS,KAAK;AACnD,OAAK,wBAAwB,SAAS,CACpC,OAAM,IAAI,OAAO;EAGnB,MAAM,YAAY,MAAM,4BAA4B,QAAQ;EAC5D,MAAM,cAAc,MAAM,UAAU,eAAe,UAAU;GAC3D,SAAS;GACT;GACA;GACA;GACA;EACD,EAAC;EAEF,MAAM,SAAS,MAAM,mBAAmB;EACxC,MAAM,eAAe;GACnB,GAAG,OAAO;GACV,GAAG;EACJ;EACD,MAAM,MAAM,MAAM,UAAU,aAAa,aAAa;AAEtD,SAAO,IAAI,SAAS,IAAI,MAAM,EAC5B,SAAS,EACP,gBAAgB,YACjB,EACF;CACF;AACF"}
1
+ {"version":3,"file":"endpoint.js","names":["htmlToVNode","html"],"sources":["../src/image.ts","../src/endpoint.ts"],"sourcesContent":["import { getConfiguredImageService, imageConfig } from \"astro:assets\";\nimport satori, { type SatoriOptions } from \"satori\";\nimport { html as htmlToVNode } from \"satori-html\";\nimport he from \"he\";\n\nimport type { LocalImageService } from \"astro\";\n\n/**\n * Convert an html string to an image\n */\nexport async function htmlToPNG(\n html: string,\n satoriOptions: SatoriOptions,\n): Promise<ReturnType<LocalImageService[\"transform\"]>> {\n // html text => vnode\n const responseTextWithDecodedHtmlEntities = he.decode(html);\n const vnode = htmlToVNode(responseTextWithDecodedHtmlEntities);\n\n // vnode => svg\n const svg = await satori(vnode as React.ReactNode, satoriOptions);\n\n // svg => buffer\n const fileBuffer = Buffer.from(svg, \"utf-8\");\n const uint8Array = new Uint8Array(\n fileBuffer.buffer,\n fileBuffer.byteOffset,\n fileBuffer.byteLength,\n );\n\n // buffer => transformed png\n return bufferToTransformedPNG(uint8Array);\n}\n\n/**\n * Convert a buffer to an image using the astro local image service\n */\nasync function bufferToTransformedPNG(\n imageBuffer: Uint8Array,\n): ReturnType<LocalImageService[\"transform\"]> {\n const imageService = (await getConfiguredImageService()) as LocalImageService;\n\n return imageService.transform(\n imageBuffer,\n { src: \"\", format: \"png\" },\n imageConfig,\n );\n}\n","import type { APIRoute } from \"astro\";\nimport { experimental_AstroContainer } from \"astro/container\";\nimport { isAstroComponentFactory } from \"astro/runtime/server/render/astro/factory.js\";\nimport { getResolvedConfig } from \"./config.js\";\nimport type { ImageOptions } from \"./types.js\";\nimport { htmlToPNG } from \"./image.js\";\n\ntype Options = {\n /**\n * We don't just type this as `AstroComponentFactory` because astro typing is\n * hard to get right and simply importing a .astro file doesn't give you\n * something typed as a factory.\n */\n template: unknown;\n /**\n * Custom \"Content-Type\" header, only used in SSR. Defaults to \"image/png\"\n */\n contentType?: string;\n imageOptionOverrides?: Partial<ImageOptions>;\n};\n\nexport function makeOpengraphDevEndpoint({\n template,\n contentType = \"text/html\",\n}: Options): APIRoute {\n return async ({ locals, params, props, request }) => {\n const config = await getResolvedConfig();\n if (config.command !== \"dev\") {\n return new Response(null, { status: 404 });\n }\n\n if (!isAstroComponentFactory(template)) {\n throw new Error(`Given is not an Astro template.`);\n }\n\n const container = await experimental_AstroContainer.create();\n const templateStr = await container.renderToString(template, {\n partial: false,\n request,\n params,\n locals,\n props,\n });\n\n return new Response(templateStr, {\n headers: {\n \"Content-Type\": contentType,\n },\n });\n };\n}\n\nexport function makeOpengraphEndpoint({\n template,\n imageOptionOverrides,\n contentType = \"image/png\",\n}: Options): APIRoute {\n return async ({ locals, params, props, request }) => {\n if (!isAstroComponentFactory(template)) {\n throw new Error(`Given is not an Astro template.`);\n }\n\n const container = await experimental_AstroContainer.create();\n const templateStr = await container.renderToString(template, {\n partial: false,\n request,\n params,\n locals,\n props,\n });\n\n const config = await getResolvedConfig();\n const imageOptions = {\n ...config.imageOptions,\n ...imageOptionOverrides,\n };\n const png = await htmlToPNG(templateStr, imageOptions);\n\n return new Response(new Uint8Array(png.data), {\n headers: {\n \"Content-Type\": contentType,\n },\n });\n };\n}\n"],"mappings":";;;;;;;;;;;AAUA,eAAsB,UACpB,QACA,eACqD;CAMrD,MAAM,MAAM,MAAM,OAHJA,KAD8B,GAAG,OAAOC,OAAK,CACG,EAGX,cAAc;CAGjE,MAAM,aAAa,OAAO,KAAK,KAAK,QAAQ;AAQ5C,QAAO,uBAPY,IAAI,WACrB,WAAW,QACX,WAAW,YACX,WAAW,WACZ,CAGwC;;;;;AAM3C,eAAe,uBACb,aAC4C;AAG5C,SAFsB,MAAM,2BAA2B,EAEnC,UAClB,aACA;EAAE,KAAK;EAAI,QAAQ;EAAO,EAC1B,YACD;;;;ACxBH,SAAgB,yBAAyB,EACvC,UACA,cAAc,eACM;AACpB,QAAO,OAAO,EAAE,QAAQ,QAAQ,OAAO,cAAc;AAEnD,OADe,MAAM,mBAAmB,EAC7B,YAAY,MACrB,QAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,CAAC;AAG5C,MAAI,CAAC,wBAAwB,SAAS,CACpC,OAAM,IAAI,MAAM,kCAAkC;EAIpD,MAAM,cAAc,OADF,MAAM,4BAA4B,QAAQ,EACxB,eAAe,UAAU;GAC3D,SAAS;GACT;GACA;GACA;GACA;GACD,CAAC;AAEF,SAAO,IAAI,SAAS,aAAa,EAC/B,SAAS,EACP,gBAAgB,aACjB,EACF,CAAC;;;AAIN,SAAgB,sBAAsB,EACpC,UACA,sBACA,cAAc,eACM;AACpB,QAAO,OAAO,EAAE,QAAQ,QAAQ,OAAO,cAAc;AACnD,MAAI,CAAC,wBAAwB,SAAS,CACpC,OAAM,IAAI,MAAM,kCAAkC;EAiBpD,MAAM,MAAM,MAAM,UAbE,OADF,MAAM,4BAA4B,QAAQ,EACxB,eAAe,UAAU;GAC3D,SAAS;GACT;GACA;GACA;GACA;GACD,CAAC,EAGmB;GACnB,IAFa,MAAM,mBAAmB,EAE5B;GACV,GAAG;GACJ,CACqD;AAEtD,SAAO,IAAI,SAAS,IAAI,WAAW,IAAI,KAAK,EAAE,EAC5C,SAAS,EACP,gBAAgB,aACjB,EACF,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { ComponentMetaTagFallbacks, ImageOptionsWithFontPaths, OpengraphImageConfig } from "./types-B1hoqgLx.js";
1
+ import { ComponentMetaTagFallbacks, ImageOptionsWithFontPaths, OpengraphImageConfig } from "./types-BGbFKpbi.js";
2
2
  import { AstroIntegration } from "astro";
3
3
 
4
4
  //#region src/integration.d.ts
5
5
  declare const _default: (config: OpengraphImageConfig) => AstroIntegration;
6
6
  //#endregion
7
- export { ComponentMetaTagFallbacks, ImageOptionsWithFontPaths, OpengraphImageConfig, _default as default };
7
+ export { type ComponentMetaTagFallbacks, type ImageOptionsWithFontPaths, type OpengraphImageConfig, _default as default };
8
8
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -22,18 +22,15 @@ function vitePluginOpengraphImageUserConfig(config) {
22
22
  }
23
23
  };
24
24
  }
25
-
26
25
  //#endregion
27
26
  //#region src/integration.ts
28
27
  var integration_default = (config) => ({
29
28
  name: "@altano/astro-opengraph",
30
29
  hooks: { async "astro:config:setup"({ updateConfig, command, addDevToolbarApp }) {
31
- const imageOptions = await config.getImageOptions();
32
- const configSerializable = {
33
- imageOptions,
30
+ updateConfig({ vite: { plugins: [vitePluginOpengraphImageUserConfig({
31
+ imageOptions: await config.getImageOptions(),
34
32
  command
35
- };
36
- updateConfig({ vite: { plugins: [vitePluginOpengraphImageUserConfig(configSerializable)] } });
33
+ })] } });
37
34
  addDevToolbarApp({
38
35
  id: "@altano/astro-opengraph",
39
36
  name: "Open Graph",
@@ -42,7 +39,7 @@ var integration_default = (config) => ({
42
39
  });
43
40
  } }
44
41
  });
45
-
46
42
  //#endregion
47
43
  export { integration_default as default };
44
+
48
45
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["id: T","config: OpengraphImageConfigSerializable","config: OpengraphImageConfig","configSerializable: OpengraphImageConfigSerializable"],"sources":["../src/virtual-user-config.ts","../src/integration.ts"],"sourcesContent":["import type { ViteUserConfig } from \"astro\";\n\nimport type { OpengraphImageConfigSerializable } from \"./types.js\";\n\nfunction resolveVirtualModuleId<T extends string>(id: T): `\\0${T}` {\n return `\\0${id}`;\n}\n\n/**\n * Vite plugin that exposes OpengraphImage user config and project context via\n * virtual modules.\n */\nexport function vitePluginOpengraphImageUserConfig(\n config: OpengraphImageConfigSerializable,\n): NonNullable<ViteUserConfig[\"plugins\"]>[number] {\n /** Map of virtual module names to their code contents as strings. */\n const modules = {\n \"virtual:astro-opengraph/user-config\": `export default ${JSON.stringify(\n config,\n )}`,\n } satisfies Record<string, string>;\n\n /** Mapping names prefixed with `\\0` to their original form. */\n const resolutionMap = Object.fromEntries(\n (Object.keys(modules) as (keyof typeof modules)[]).map((key) => [\n resolveVirtualModuleId(key),\n key,\n ]),\n );\n\n return {\n name: \"vite-plugin-astro-opengraph-user-config\",\n resolveId(id): string | void {\n if (id in modules) return resolveVirtualModuleId(id);\n },\n load(id): string | void {\n const resolution = resolutionMap[id];\n if (resolution) return modules[resolution];\n },\n };\n}\n","import type { AstroIntegration } from \"astro\";\nimport type {\n OpengraphImageConfig,\n OpengraphImageConfigSerializable,\n} from \"./types.js\";\nimport { vitePluginOpengraphImageUserConfig } from \"./virtual-user-config.js\";\n\nexport default (config: OpengraphImageConfig): AstroIntegration => ({\n name: \"@altano/astro-opengraph\",\n hooks: {\n async \"astro:config:setup\"({\n updateConfig,\n command,\n addDevToolbarApp,\n }): Promise<void> {\n const imageOptions = await config.getImageOptions();\n const configSerializable: OpengraphImageConfigSerializable = {\n imageOptions,\n command,\n };\n updateConfig({\n vite: {\n // Shove the serializable config into the virtual module for later\n // retrieval in the middleware\n plugins: [vitePluginOpengraphImageUserConfig(configSerializable)],\n },\n });\n addDevToolbarApp({\n id: \"@altano/astro-opengraph\",\n name: \"Open Graph\",\n // icon: \"🌠\",\n icon: \"image\",\n // We don't use `@altano/astro-opengraph/toolbar` because that won't\n // resolve when serving the test fixture for e2e runs (`pnpm\n // test:e2e:server`)\n entrypoint: new URL(\"./toolbar/index.js\", import.meta.url),\n });\n },\n },\n});\n"],"mappings":";AAIA,SAAS,uBAAyCA,IAAiB;AACjE,SAAQ,IAAI,GAAG;AAChB;;;;;AAMD,SAAgB,mCACdC,QACgD;;CAEhD,MAAM,UAAU,EACd,wCAAwC,iBAAiB,KAAK,UAC5D,OACD,CAAC,EACH;;CAGD,MAAM,gBAAgB,OAAO,YAC3B,AAAC,OAAO,KAAK,QAAQ,CAA8B,IAAI,CAAC,QAAQ,CAC9D,uBAAuB,IAAI,EAC3B,GACD,EAAC,CACH;AAED,QAAO;EACL,MAAM;EACN,UAAU,IAAmB;AAC3B,OAAI,MAAM,QAAS,QAAO,uBAAuB,GAAG;EACrD;EACD,KAAK,IAAmB;GACtB,MAAM,aAAa,cAAc;AACjC,OAAI,WAAY,QAAO,QAAQ;EAChC;CACF;AACF;;;;ACjCD,0BAAe,CAACC,YAAoD;CAClE,MAAM;CACN,OAAO,EACL,MAAM,qBAAqB,EACzB,cACA,SACA,kBACD,EAAiB;EAChB,MAAM,eAAe,MAAM,OAAO,iBAAiB;EACnD,MAAMC,qBAAuD;GAC3D;GACA;EACD;AACD,eAAa,EACX,MAAM,EAGJ,SAAS,CAAC,mCAAmC,mBAAmB,AAAC,EAClE,EACF,EAAC;AACF,mBAAiB;GACf,IAAI;GACJ,MAAM;GAEN,MAAM;GAIN,YAAY,IAAI,IAAI,sBAAsB,OAAO,KAAK;EACvD,EAAC;CACH,EACF;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/virtual-user-config.ts","../src/integration.ts"],"sourcesContent":["import type { ViteUserConfig } from \"astro\";\n\nimport type { OpengraphImageConfigSerializable } from \"./types.js\";\n\nfunction resolveVirtualModuleId<T extends string>(id: T): `\\0${T}` {\n return `\\0${id}`;\n}\n\n/**\n * Vite plugin that exposes OpengraphImage user config and project context via\n * virtual modules.\n */\nexport function vitePluginOpengraphImageUserConfig(\n config: OpengraphImageConfigSerializable,\n): NonNullable<ViteUserConfig[\"plugins\"]>[number] {\n /** Map of virtual module names to their code contents as strings. */\n const modules = {\n \"virtual:astro-opengraph/user-config\": `export default ${JSON.stringify(\n config,\n )}`,\n } satisfies Record<string, string>;\n\n /** Mapping names prefixed with `\\0` to their original form. */\n const resolutionMap = Object.fromEntries(\n (Object.keys(modules) as (keyof typeof modules)[]).map((key) => [\n resolveVirtualModuleId(key),\n key,\n ]),\n );\n\n return {\n name: \"vite-plugin-astro-opengraph-user-config\",\n resolveId(id): string | void {\n if (id in modules) return resolveVirtualModuleId(id);\n },\n load(id): string | void {\n const resolution = resolutionMap[id];\n if (resolution) return modules[resolution];\n },\n };\n}\n","import type { AstroIntegration } from \"astro\";\nimport type {\n OpengraphImageConfig,\n OpengraphImageConfigSerializable,\n} from \"./types.js\";\nimport { vitePluginOpengraphImageUserConfig } from \"./virtual-user-config.js\";\n\nexport default (config: OpengraphImageConfig): AstroIntegration => ({\n name: \"@altano/astro-opengraph\",\n hooks: {\n async \"astro:config:setup\"({\n updateConfig,\n command,\n addDevToolbarApp,\n }): Promise<void> {\n const imageOptions = await config.getImageOptions();\n const configSerializable: OpengraphImageConfigSerializable = {\n imageOptions,\n command,\n };\n updateConfig({\n vite: {\n // Shove the serializable config into the virtual module for later\n // retrieval in the middleware\n plugins: [vitePluginOpengraphImageUserConfig(configSerializable)],\n },\n });\n addDevToolbarApp({\n id: \"@altano/astro-opengraph\",\n name: \"Open Graph\",\n // icon: \"🌠\",\n icon: \"image\",\n // We don't use `@altano/astro-opengraph/toolbar` because that won't\n // resolve when serving the test fixture for e2e runs (`pnpm\n // test:e2e:server`)\n entrypoint: new URL(\"./toolbar/index.js\", import.meta.url),\n });\n },\n },\n});\n"],"mappings":";AAIA,SAAS,uBAAyC,IAAiB;AACjE,QAAO,KAAK;;;;;;AAOd,SAAgB,mCACd,QACgD;;CAEhD,MAAM,UAAU,EACd,uCAAuC,kBAAkB,KAAK,UAC5D,OACD,IACF;;CAGD,MAAM,gBAAgB,OAAO,YAC1B,OAAO,KAAK,QAAQ,CAA8B,KAAK,QAAQ,CAC9D,uBAAuB,IAAI,EAC3B,IACD,CAAC,CACH;AAED,QAAO;EACL,MAAM;EACN,UAAU,IAAmB;AAC3B,OAAI,MAAM,QAAS,QAAO,uBAAuB,GAAG;;EAEtD,KAAK,IAAmB;GACtB,MAAM,aAAa,cAAc;AACjC,OAAI,WAAY,QAAO,QAAQ;;EAElC;;;;AChCH,IAAA,uBAAgB,YAAoD;CAClE,MAAM;CACN,OAAO,EACL,MAAM,qBAAqB,EACzB,cACA,SACA,oBACgB;AAMhB,eAAa,EACX,MAAM,EAGJ,SAAS,CAAC,mCAR+C;GAC3D,cAFmB,MAAM,OAAO,iBAAiB;GAGjD;GACD,CAKmE,CAAC,EAClE,EACF,CAAC;AACF,mBAAiB;GACf,IAAI;GACJ,MAAM;GAEN,MAAM;GAIN,YAAY,IAAI,IAAI,sBAAsB,OAAO,KAAK,IAAI;GAC3D,CAAC;IAEL;CACF"}
@@ -2,7 +2,6 @@ import { render } from "preact";
2
2
  import { defineToolbarApp } from "astro/toolbar";
3
3
  import { useCallback, useEffect, useRef, useState } from "preact/hooks";
4
4
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
5
-
6
5
  //#region src/toolbar/styles.tsx
7
6
  const styles = `
8
7
  :host astro-dev-toolbar-window {
@@ -34,7 +33,6 @@ const styles = `
34
33
  transition: max-width 0.1s;
35
34
  }
36
35
  `;
37
-
38
36
  //#endregion
39
37
  //#region src/toolbar/components/Summary.tsx
40
38
  function Summary({ children }) {
@@ -47,7 +45,6 @@ function Summary({ children }) {
47
45
  children
48
46
  });
49
47
  }
50
-
51
48
  //#endregion
52
49
  //#region src/toolbar/components/ExternalLinkicon.tsx
53
50
  function ExternalLinkicon({ width = 27, height = 27, fill = "#020202" }) {
@@ -81,34 +78,29 @@ function ExternalLinkicon({ width = 27, height = 27, fill = "#020202" }) {
81
78
  })
82
79
  });
83
80
  }
84
-
85
81
  //#endregion
86
82
  //#region src/toolbar/components/LinkOrText.tsx
87
83
  function LinkOrText({ maybeLinkText }) {
88
84
  let parsedMaybeLink = null;
89
85
  try {
90
- if (maybeLinkText != null) {
91
- const url = new URL(maybeLinkText);
92
- parsedMaybeLink = /* @__PURE__ */ jsxs("a", {
93
- href: url.toString(),
94
- target: "_blank",
95
- children: [
96
- maybeLinkText,
97
- " ",
98
- /* @__PURE__ */ jsx(ExternalLinkicon, {
99
- width: 10,
100
- height: 10,
101
- fill: "white"
102
- })
103
- ]
104
- });
105
- }
86
+ if (maybeLinkText != null) parsedMaybeLink = /* @__PURE__ */ jsxs("a", {
87
+ href: new URL(maybeLinkText).toString(),
88
+ target: "_blank",
89
+ children: [
90
+ maybeLinkText,
91
+ " ",
92
+ /* @__PURE__ */ jsx(ExternalLinkicon, {
93
+ width: 10,
94
+ height: 10,
95
+ fill: "white"
96
+ })
97
+ ]
98
+ });
106
99
  } catch (_) {
107
100
  parsedMaybeLink = maybeLinkText;
108
101
  }
109
102
  return parsedMaybeLink;
110
103
  }
111
-
112
104
  //#endregion
113
105
  //#region src/toolbar/hooks/useMetaTagInfo.tsx
114
106
  const useHeadObserver = () => {
@@ -129,11 +121,9 @@ const useHeadObserver = () => {
129
121
  return headRef;
130
122
  };
131
123
  function useMetaTagInfo() {
132
- const headRef = useHeadObserver();
133
- const opengraphMetaTags = headRef?.current?.querySelectorAll("meta[property^='og:']") ?? [];
124
+ const opengraphMetaTags = useHeadObserver()?.current?.querySelectorAll("meta[property^='og:']") ?? [];
134
125
  return Array.from(opengraphMetaTags).map((tag) => [tag.getAttribute("content"), tag.getAttribute("property")]);
135
126
  }
136
-
137
127
  //#endregion
138
128
  //#region src/toolbar/components/MetaTags.tsx
139
129
  function MetaTags() {
@@ -164,7 +154,6 @@ function MetaTagContent({ tag }) {
164
154
  children: /* @__PURE__ */ jsx(LinkOrText, { maybeLinkText: content })
165
155
  })] });
166
156
  }
167
-
168
157
  //#endregion
169
158
  //#region src/toolbar/hooks/useHoverState.tsx
170
159
  function useHoverState(setHoverState) {
@@ -178,7 +167,6 @@ function useHoverState(setHoverState) {
178
167
  }, [setHoverState]);
179
168
  return ref;
180
169
  }
181
-
182
170
  //#endregion
183
171
  //#region src/toolbar/hooks/useImageURL.tsx
184
172
  function useImageURL() {
@@ -188,12 +176,10 @@ function useImageURL() {
188
176
  }
189
177
  function useImageURLIfAvailable() {
190
178
  const [imageUrlRef] = useState(() => {
191
- const meta = document.querySelector("meta[property=\"og:image\"]");
192
- return meta?.getAttribute("content") ?? null;
179
+ return document.querySelector("meta[property=\"og:image\"]")?.getAttribute("content") ?? null;
193
180
  });
194
181
  return imageUrlRef;
195
182
  }
196
-
197
183
  //#endregion
198
184
  //#region src/toolbar/components/Image.tsx
199
185
  function Image({ imageSize, handleLoadError }) {
@@ -216,32 +202,27 @@ function Image({ imageSize, handleLoadError }) {
216
202
  })
217
203
  });
218
204
  }
219
-
220
205
  //#endregion
221
206
  //#region src/toolbar/components/ZoomLabel.tsx
222
207
  function ZoomLabel({ imageSize }) {
223
- const formattedNumber = (imageSize / 100).toLocaleString(void 0, { minimumFractionDigits: 2 });
224
- return `${formattedNumber}x`;
208
+ return `${(imageSize / 100).toLocaleString(void 0, { minimumFractionDigits: 2 })}x`;
225
209
  }
226
-
227
210
  //#endregion
228
211
  //#region src/toolbar/components/ZoomButton.tsx
229
212
  function ZoomButton({ value, imageSize, setImageSize }) {
230
- const isSelected = value === imageSize;
231
213
  return /* @__PURE__ */ jsx("astro-dev-toolbar-button", {
232
214
  size: "small",
233
215
  style: {
234
216
  padding: 0,
235
217
  margin: 0
236
218
  },
237
- buttonStyle: isSelected ? "gray" : "ghost",
219
+ buttonStyle: value === imageSize ? "gray" : "ghost",
238
220
  className: "zoom-button",
239
221
  role: "radio",
240
222
  onClick: () => setImageSize(value),
241
223
  children: /* @__PURE__ */ jsx(ZoomLabel, { imageSize: value })
242
224
  });
243
225
  }
244
-
245
226
  //#endregion
246
227
  //#region src/toolbar/components/ToolbarSection.tsx
247
228
  function ToolbarSection({ icon, children }) {
@@ -262,7 +243,6 @@ function ToolbarSection({ icon, children }) {
262
243
  }), children]
263
244
  });
264
245
  }
265
-
266
246
  //#endregion
267
247
  //#region src/toolbar/components/ImageZoomToolbar.tsx
268
248
  function ImageZoomToolbar({ isHovered, imageSize, setImageSize }) {
@@ -296,7 +276,6 @@ function ImageZoomToolbar({ isHovered, imageSize, setImageSize }) {
296
276
  ] })
297
277
  });
298
278
  }
299
-
300
279
  //#endregion
301
280
  //#region src/toolbar/components/CopyImageUrlButton.tsx
302
281
  function CopyImageUrlButton() {
@@ -331,7 +310,6 @@ function CopyImageUrlButton() {
331
310
  })
332
311
  });
333
312
  }
334
-
335
313
  //#endregion
336
314
  //#region src/toolbar/components/ImageSection.tsx
337
315
  function ImageSection({ isHovered, handleLoadError }) {
@@ -354,7 +332,6 @@ function ImageSection({ isHovered, handleLoadError }) {
354
332
  })]
355
333
  })] });
356
334
  }
357
-
358
335
  //#endregion
359
336
  //#region src/toolbar/components/Error.tsx
360
337
  function Error$1({ message, icon }) {
@@ -377,14 +354,11 @@ function Error$1({ message, icon }) {
377
354
  ]
378
355
  });
379
356
  }
380
-
381
357
  //#endregion
382
358
  //#region src/toolbar/components/getRelativeUrl.tsx
383
359
  function getRelativeUrl(absoluteUrl) {
384
- const url = new URL(absoluteUrl);
385
- return url.pathname;
360
+ return new URL(absoluteUrl).pathname;
386
361
  }
387
-
388
362
  //#endregion
389
363
  //#region src/toolbar/components/ToolbarApp.tsx
390
364
  function ToolbarApp() {
@@ -410,31 +384,28 @@ function ToolbarApp() {
410
384
  })]
411
385
  }), /* @__PURE__ */ jsxs("details", { children: [/* @__PURE__ */ jsx(Summary, { children: "Meta Tags" }), /* @__PURE__ */ jsx(MetaTags, {})] })] });
412
386
  }
413
-
414
387
  //#endregion
415
388
  //#region src/toolbar/components/ToolbarAppWindow.tsx
416
389
  function ToolbarAppWindow() {
417
390
  return /* @__PURE__ */ jsxs("astro-dev-toolbar-window", { children: [/* @__PURE__ */ jsx("style", { children: styles }), /* @__PURE__ */ jsx(ToolbarApp, {})] });
418
391
  }
419
-
420
392
  //#endregion
421
393
  //#region src/toolbar/index.tsx
422
394
  const SESSION_KEY_OPEN = "@altano/astro-opengraph/toolbar:is-open";
423
- const app = defineToolbarApp({ init(canvas, app$1) {
424
- app$1.onToggled((event) => {
395
+ const app = defineToolbarApp({ init(canvas, app) {
396
+ app.onToggled((event) => {
425
397
  if (event.state) {
426
398
  sessionStorage.setItem(SESSION_KEY_OPEN, "true");
427
399
  render(/* @__PURE__ */ jsx(ToolbarAppWindow, {}), canvas);
428
400
  } else sessionStorage.removeItem(SESSION_KEY_OPEN);
429
401
  });
430
- app$1.toggleNotification({
402
+ app.toggleNotification({
431
403
  state: document.querySelector("meta[property=\"og:image\"]") != null,
432
404
  level: "info"
433
405
  });
434
- if (sessionStorage.getItem(SESSION_KEY_OPEN) != null) app$1.toggleState({ state: true });
406
+ if (sessionStorage.getItem(SESSION_KEY_OPEN) != null) app.toggleState({ state: true });
435
407
  } });
436
- var toolbar_default = app;
437
-
438
408
  //#endregion
439
- export { toolbar_default as default };
409
+ export { app as default };
410
+
440
411
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["parsedMaybeLink: LinkOrTextType","tag: Element","setHoverState: (isHover: boolean) => void","handleClick: MouseEventHandler<DevToolbarButton>","Error","absoluteUrl: string","Error","app: DevToolbarApp","app"],"sources":["../../src/toolbar/styles.tsx","../../src/toolbar/components/Summary.tsx","../../src/toolbar/components/ExternalLinkicon.tsx","../../src/toolbar/components/LinkOrText.tsx","../../src/toolbar/hooks/useMetaTagInfo.tsx","../../src/toolbar/components/MetaTags.tsx","../../src/toolbar/hooks/useHoverState.tsx","../../src/toolbar/hooks/useImageURL.tsx","../../src/toolbar/components/Image.tsx","../../src/toolbar/components/ZoomLabel.tsx","../../src/toolbar/components/ZoomButton.tsx","../../src/toolbar/components/ToolbarSection.tsx","../../src/toolbar/components/ImageZoomToolbar.tsx","../../src/toolbar/components/CopyImageUrlButton.tsx","../../src/toolbar/components/ImageSection.tsx","../../src/toolbar/components/Error.tsx","../../src/toolbar/components/getRelativeUrl.tsx","../../src/toolbar/components/ToolbarApp.tsx","../../src/toolbar/components/ToolbarAppWindow.tsx","../../src/toolbar/index.tsx"],"sourcesContent":["export const styles = /* css */ `\n :host astro-dev-toolbar-window {\n max-height: calc(100vh - 80px);\n overflow-y: auto;\n }\n\n button {\n background: none;\n color: inherit;\n border: none;\n font: inherit;\n cursor: pointer;\n outline: inherit;\n }\n\n details {\n margin-block-end: 10px;\n }\n details:last-of-type {\n margin-block-end: 0;\n }\n\n details[open] summary, .image {\n margin-block-end: 7px;\n }\n\n .image img {\n transition: max-width 0.1s;\n }\n`;\n","import type Preact from \"preact\";\n\nexport function Summary({\n children,\n}: {\n children: string;\n}): Preact.JSX.Element {\n return (\n <summary\n style={{\n cursor: \"pointer\",\n fontWeight: 700,\n color: \"white\",\n }}\n >\n {children}\n </summary>\n );\n}\n","import type Preact from \"preact\";\n\nexport function ExternalLinkicon({\n width = 27,\n height = 27,\n fill = \"#020202\",\n}: {\n width?: number;\n height?: number;\n fill?: string;\n}): Preact.JSX.Element {\n return (\n <span\n style={{\n display: \"inline-block\",\n width,\n height,\n }}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 120 120\">\n <path d=\"M120.09 16.696H60.256V.096L120.09.09z\" fill={fill} />\n <path\n d=\"M57.99 48.64l42.573-42.574 13.475 13.475-42.574 42.58z\"\n fill={fill}\n />\n <path\n d=\"M119.98.107l.02 59.83-16.59.013-.02-59.846zM3 23.5h17v87H3zm83.49 52.56h17V113h-17z\"\n fill={fill}\n />\n <path d=\"M3 16.692h40.655v17H3zM3 96h100.49v17H3z\" fill={fill} />\n </svg>\n </span>\n );\n}\n","import type Preact from \"preact\";\nimport { ExternalLinkicon } from \"./ExternalLinkicon.js\";\n\ntype LinkOrTextType = Preact.JSX.Element | string | null;\n\nexport function LinkOrText({\n maybeLinkText,\n}: {\n maybeLinkText: string | null;\n}): LinkOrTextType {\n let parsedMaybeLink: LinkOrTextType = null;\n try {\n if (maybeLinkText != null) {\n const url = new URL(maybeLinkText);\n parsedMaybeLink = (\n <a href={url.toString()} target=\"_blank\">\n {maybeLinkText}{\" \"}\n <ExternalLinkicon width={10} height={10} fill=\"white\" />\n </a>\n );\n }\n } catch (_) {\n parsedMaybeLink = maybeLinkText;\n }\n return parsedMaybeLink;\n}\n","import { useEffect, useRef, useState } from \"preact/hooks\";\n\nexport type MetaTagInfo = [content: string | null, property: string | null];\n\nconst useHeadObserver = (): React.RefObject<HTMLHeadElement | null> => {\n const [_generation, setGeneration] = useState<number>(0);\n const forceRerender = (): void => setGeneration((old) => ++old);\n const headRef = useRef(document.querySelector(\"head\"));\n\n // useEffect(() => {\n // console.log({ generation });\n // }, [generation]);\n\n useEffect(() => {\n // console.log({ \"headRef.current\": headRef.current });\n if (headRef.current == null) {\n // assume we must have a head by now, and if we don't, we will never get\n // one.\n return;\n }\n const observer = new MutationObserver(forceRerender);\n observer.observe(headRef.current, {\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n return () => observer.disconnect();\n }, []);\n\n return headRef;\n};\n\nexport function useMetaTagInfo(): MetaTagInfo[] {\n const headRef = useHeadObserver();\n const opengraphMetaTags =\n headRef?.current?.querySelectorAll(\"meta[property^='og:']\") ?? [];\n // console.log({\n // opengraphMetaTags: opengraphMetaTags,\n // opengraphMetaTagsLength: opengraphMetaTags.length,\n // });\n return Array.from(opengraphMetaTags).map(\n (tag: Element): MetaTagInfo => [\n tag.getAttribute(\"content\"),\n tag.getAttribute(\"property\"),\n ],\n );\n}\n","import type Preact from \"preact\";\nimport { LinkOrText } from \"./LinkOrText.js\";\nimport { useMetaTagInfo, type MetaTagInfo } from \"../hooks/useMetaTagInfo.js\";\n\nexport function MetaTags(): Preact.JSX.Element {\n const tags = useMetaTagInfo();\n\n return (\n <dl\n data-testid=\"astro-opengraph-toolbar\"\n style={{\n margin: 0,\n display: \"grid\",\n gridTemplateColumns: \"max-content 1fr\",\n gap: 7,\n columnGap: 13,\n }}\n >\n {tags.map((tag) => (\n <MetaTagContent key={tag[1]} tag={tag} />\n ))}\n </dl>\n );\n}\n\nfunction MetaTagContent({ tag }: { tag: MetaTagInfo }): Preact.JSX.Element {\n const [content, property] = tag;\n return (\n <>\n <dt\n style={{\n color: \"white\",\n textAlign: \"right\",\n fontWeight: 500,\n }}\n >\n {property}\n </dt>\n <dd style={{ margin: 0 }}>\n <LinkOrText maybeLinkText={content} />\n </dd>\n </>\n );\n}\n","import type Preact from \"preact\";\nimport { useRef, useEffect } from \"preact/hooks\";\n\nexport function useHoverState<TElement extends HTMLElement>(\n setHoverState: (isHover: boolean) => void,\n): Preact.RefObject<TElement> {\n const ref = useRef<TElement>(null);\n\n useEffect(() => {\n const controller = new AbortController();\n const { signal } = controller;\n ref.current?.addEventListener(\"mouseenter\", () => setHoverState(true), {\n signal,\n });\n ref.current?.addEventListener(\"mouseleave\", () => setHoverState(false), {\n signal,\n });\n\n return () => controller.abort();\n }, [setHoverState]);\n\n return ref;\n}\n","import { useState } from \"preact/hooks\";\n\nexport function useImageURL(): string {\n const imageUrl = useImageURLIfAvailable();\n if (imageUrl == null) {\n throw new Error(\n `Shouldn't be rendering this component without an image URL`,\n );\n }\n return imageUrl;\n}\n\nexport function useImageURLIfAvailable(): string | null {\n const [imageUrlRef] = useState(() => {\n const meta = document.querySelector('meta[property=\"og:image\"]');\n return meta?.getAttribute(\"content\") ?? null;\n });\n return imageUrlRef;\n}\n","import type Preact from \"preact\";\nimport { useImageURL } from \"../hooks/useImageURL.js\";\n\nexport function Image({\n imageSize,\n handleLoadError,\n}: {\n imageSize: number;\n handleLoadError: () => void;\n}): Preact.JSX.Element {\n const imageUrl = useImageURL();\n return (\n <div className=\"image\">\n <a href={imageUrl} target=\"_blank\" title=\"Open image in new tab\">\n <img\n onError={handleLoadError}\n alt=\"Open Graph\"\n src={imageUrl}\n style={{\n maxHeight: \"100%\",\n maxWidth: `${imageSize}%`,\n }}\n />\n </a>\n </div>\n );\n}\n","export function ZoomLabel({ imageSize }: { imageSize: number }): string {\n const formattedNumber = (imageSize / 100).toLocaleString(undefined, {\n minimumFractionDigits: 2,\n });\n return `${formattedNumber}x`;\n}\n","import type Preact from \"preact\";\nimport { ZoomLabel } from \"./ZoomLabel.js\";\n\nexport function ZoomButton({\n value,\n imageSize,\n setImageSize,\n}: {\n value: number;\n imageSize: number;\n setImageSize: (size: number) => void;\n}): Preact.JSX.Element {\n const isSelected = value === imageSize;\n return (\n <astro-dev-toolbar-button\n size=\"small\"\n style={{ padding: 0, margin: 0 }}\n buttonStyle={isSelected ? \"gray\" : \"ghost\"}\n className=\"zoom-button\"\n role=\"radio\"\n onClick={() => setImageSize(value)}\n >\n <ZoomLabel imageSize={value} />\n </astro-dev-toolbar-button>\n );\n}\n","import type { ComponentChildren } from \"preact\";\nimport type Preact from \"preact\";\n\nexport function ToolbarSection({\n icon,\n children,\n}: {\n icon: Preact.JSX.Element;\n children: ComponentChildren;\n}): Preact.JSX.Element {\n return (\n <div\n style={{\n fontSize: 12,\n display: \"flex\",\n alignItems: \"center\",\n columnGap: 5,\n }}\n >\n <div\n style={{\n display: \"inline-block\",\n width: 12,\n height: 12,\n }}\n >\n {icon}\n </div>\n {children}\n </div>\n );\n}\n","import type Preact from \"preact\";\nimport { ZoomButton } from \"./ZoomButton.js\";\nimport { ToolbarSection } from \"./ToolbarSection.js\";\n\nexport function ImageZoomToolbar({\n isHovered,\n imageSize,\n setImageSize,\n}: {\n isHovered: boolean;\n imageSize: number;\n setImageSize: (size: number) => void;\n}): Preact.JSX.Element {\n return (\n <ToolbarSection icon={<astro-dev-toolbar-icon icon=\"gear\" />}>\n {!isHovered ? (\n <ZoomButton\n value={imageSize}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n ) : (\n <>\n <ZoomButton\n value={25}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n <ZoomButton\n value={50}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n <ZoomButton\n value={75}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n <ZoomButton\n value={100}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n </>\n )}\n </ToolbarSection>\n );\n}\n","import { useState, useRef, useEffect, useCallback } from \"preact/hooks\";\nimport type Preact from \"preact\";\nimport type { MouseEventHandler } from \"preact/compat\";\nimport type { DevToolbarButton } from \"astro/runtime/client/dev-toolbar/ui-library/button.js\";\nimport { useImageURL } from \"../hooks/useImageURL.js\";\nimport { ToolbarSection } from \"./ToolbarSection.js\";\n\ntype Timer = ReturnType<typeof setTimeout>;\n\nexport function CopyImageUrlButton(): Preact.JSX.Element {\n const imageUrl = useImageURL();\n const [wasRecentlyClicked, setWasRecentlyClicked] = useState(false);\n const checkTimer = useRef<Timer | null>(null);\n\n useEffect(() => {\n if (wasRecentlyClicked && checkTimer.current == null) {\n checkTimer.current = setTimeout(() => {\n setWasRecentlyClicked(false);\n // TODO investigate\n // eslint-disable-next-line react-compiler/react-compiler\n checkTimer.current = null;\n }, 3_000);\n }\n }, [wasRecentlyClicked]);\n\n const handleClick: MouseEventHandler<DevToolbarButton> = useCallback(\n (evt) => {\n // Copy the text inside the text field\n void navigator.clipboard.writeText(imageUrl);\n setWasRecentlyClicked(true);\n evt.stopPropagation();\n evt.preventDefault();\n },\n [imageUrl],\n );\n\n return (\n <ToolbarSection icon={<astro-dev-toolbar-icon icon=\"copy\" />}>\n <div style={{ display: \"flex\", alignItems: \"center\" }}>\n <astro-dev-toolbar-button\n size=\"small\"\n buttonStyle=\"gray\"\n onClick={handleClick}\n >\n {wasRecentlyClicked ? \"Copied to clipboard\" : \"Copy image URL\"}\n </astro-dev-toolbar-button>\n </div>\n </ToolbarSection>\n );\n}\n","import { Image } from \"./Image.js\";\nimport { ImageZoomToolbar } from \"./ImageZoomToolbar.js\";\nimport { CopyImageUrlButton } from \"./CopyImageUrlButton.js\";\nimport type Preact from \"preact\";\nimport { useState } from \"preact/hooks\";\n\nexport function ImageSection({\n isHovered,\n handleLoadError,\n}: {\n isHovered: boolean;\n handleLoadError: () => void;\n}): Preact.JSX.Element {\n const [imageSize, setImageSize] = useState(100);\n\n return (\n <>\n <Image imageSize={imageSize} handleLoadError={handleLoadError} />\n <div\n data-testid=\"image-section-toolbar\"\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n columnGap: 15,\n }}\n >\n <CopyImageUrlButton />\n <ImageZoomToolbar\n isHovered={isHovered}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n </div>\n </>\n );\n}\n","import type { Icon } from \"astro/runtime/client/dev-toolbar/ui-library/icons.js\";\nimport type Preact from \"preact\";\n\nexport function Error({\n message,\n icon,\n}: {\n message: string;\n icon: Icon;\n}): Preact.JSX.Element {\n return (\n <div\n style={{\n display: \"flex\",\n gap: 10,\n alignItems: \"center\",\n }}\n >\n <astro-dev-toolbar-icon style={{ width: 24, height: 24 }} icon={icon} />{\" \"}\n {message}\n </div>\n );\n}\n","export function getRelativeUrl(absoluteUrl: string): string {\n const url = new URL(absoluteUrl);\n return url.pathname;\n}\n","import type Preact from \"preact\";\nimport { useState } from \"preact/hooks\";\nimport { Summary } from \"./Summary.js\";\nimport { MetaTags } from \"./MetaTags.js\";\nimport { useHoverState } from \"../hooks/useHoverState.js\";\nimport { useImageURLIfAvailable } from \"../hooks/useImageURL.js\";\nimport { ImageSection } from \"./ImageSection.js\";\nimport { Error } from \"./Error.js\";\nimport { getRelativeUrl } from \"./getRelativeUrl.js\";\n\nexport function ToolbarApp(): Preact.JSX.Element {\n const [isImageDetailsHovered, setIsImageDetailsHovered] = useState(false);\n const imageDetailsRef = useHoverState<HTMLDetailsElement>(\n setIsImageDetailsHovered,\n );\n const imageUrl = useImageURLIfAvailable();\n const [imageLoadStatus, setImageLoadStatus] = useState<\"pending\" | \"error\">(\n \"pending\",\n );\n\n if (imageUrl == null) {\n return (\n <Error icon=\"warning\" message=\"No Open Graph image found on this page\" />\n );\n } else if (imageLoadStatus === \"error\") {\n return (\n <Error\n icon=\"bug\"\n message={`Error loading image at ${getRelativeUrl(imageUrl)}`}\n />\n );\n }\n\n return (\n <>\n <details open className=\"image\" ref={imageDetailsRef}>\n <Summary>Image</Summary>\n <ImageSection\n isHovered={isImageDetailsHovered}\n handleLoadError={() => setImageLoadStatus(\"error\")}\n />\n </details>\n\n <details>\n <Summary>Meta Tags</Summary>\n <MetaTags />\n </details>\n </>\n );\n}\n","import type Preact from \"preact\";\nimport { styles } from \"../styles.js\";\nimport { ToolbarApp } from \"./ToolbarApp.js\";\n\nexport function ToolbarAppWindow(): Preact.JSX.Element {\n return (\n <astro-dev-toolbar-window>\n <style>{styles}</style>\n <ToolbarApp />\n </astro-dev-toolbar-window>\n );\n}\n","import { render } from \"preact\";\n\nimport { defineToolbarApp } from \"astro/toolbar\";\nimport { ToolbarAppWindow } from \"./components/ToolbarAppWindow.js\";\nimport type { DevToolbarApp } from \"astro\";\n\nconst SESSION_KEY_OPEN = \"@altano/astro-opengraph/toolbar:is-open\";\n\nconst app: DevToolbarApp = defineToolbarApp({\n init(canvas, app) {\n app.onToggled((event) => {\n if (event.state) {\n sessionStorage.setItem(SESSION_KEY_OPEN, \"true\");\n render(<ToolbarAppWindow />, canvas);\n } else {\n sessionStorage.removeItem(SESSION_KEY_OPEN);\n }\n });\n\n app.toggleNotification({\n state: document.querySelector('meta[property=\"og:image\"]') != null,\n level: \"info\",\n });\n\n if (sessionStorage.getItem(SESSION_KEY_OPEN) != null) {\n app.toggleState({ state: true });\n }\n },\n});\n\nexport default app;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["Error","Error"],"sources":["../../src/toolbar/styles.tsx","../../src/toolbar/components/Summary.tsx","../../src/toolbar/components/ExternalLinkicon.tsx","../../src/toolbar/components/LinkOrText.tsx","../../src/toolbar/hooks/useMetaTagInfo.tsx","../../src/toolbar/components/MetaTags.tsx","../../src/toolbar/hooks/useHoverState.tsx","../../src/toolbar/hooks/useImageURL.tsx","../../src/toolbar/components/Image.tsx","../../src/toolbar/components/ZoomLabel.tsx","../../src/toolbar/components/ZoomButton.tsx","../../src/toolbar/components/ToolbarSection.tsx","../../src/toolbar/components/ImageZoomToolbar.tsx","../../src/toolbar/components/CopyImageUrlButton.tsx","../../src/toolbar/components/ImageSection.tsx","../../src/toolbar/components/Error.tsx","../../src/toolbar/components/getRelativeUrl.tsx","../../src/toolbar/components/ToolbarApp.tsx","../../src/toolbar/components/ToolbarAppWindow.tsx","../../src/toolbar/index.tsx"],"sourcesContent":["export const styles = /* css */ `\n :host astro-dev-toolbar-window {\n max-height: calc(100vh - 80px);\n overflow-y: auto;\n }\n\n button {\n background: none;\n color: inherit;\n border: none;\n font: inherit;\n cursor: pointer;\n outline: inherit;\n }\n\n details {\n margin-block-end: 10px;\n }\n details:last-of-type {\n margin-block-end: 0;\n }\n\n details[open] summary, .image {\n margin-block-end: 7px;\n }\n\n .image img {\n transition: max-width 0.1s;\n }\n`;\n","import type Preact from \"preact\";\n\nexport function Summary({\n children,\n}: {\n children: string;\n}): Preact.JSX.Element {\n return (\n <summary\n style={{\n cursor: \"pointer\",\n fontWeight: 700,\n color: \"white\",\n }}\n >\n {children}\n </summary>\n );\n}\n","import type Preact from \"preact\";\n\nexport function ExternalLinkicon({\n width = 27,\n height = 27,\n fill = \"#020202\",\n}: {\n width?: number;\n height?: number;\n fill?: string;\n}): Preact.JSX.Element {\n return (\n <span\n style={{\n display: \"inline-block\",\n width,\n height,\n }}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 120 120\">\n <path d=\"M120.09 16.696H60.256V.096L120.09.09z\" fill={fill} />\n <path\n d=\"M57.99 48.64l42.573-42.574 13.475 13.475-42.574 42.58z\"\n fill={fill}\n />\n <path\n d=\"M119.98.107l.02 59.83-16.59.013-.02-59.846zM3 23.5h17v87H3zm83.49 52.56h17V113h-17z\"\n fill={fill}\n />\n <path d=\"M3 16.692h40.655v17H3zM3 96h100.49v17H3z\" fill={fill} />\n </svg>\n </span>\n );\n}\n","import type Preact from \"preact\";\nimport { ExternalLinkicon } from \"./ExternalLinkicon.js\";\n\ntype LinkOrTextType = Preact.JSX.Element | string | null;\n\nexport function LinkOrText({\n maybeLinkText,\n}: {\n maybeLinkText: string | null;\n}): LinkOrTextType {\n let parsedMaybeLink: LinkOrTextType = null;\n try {\n if (maybeLinkText != null) {\n const url = new URL(maybeLinkText);\n parsedMaybeLink = (\n <a href={url.toString()} target=\"_blank\">\n {maybeLinkText}{\" \"}\n <ExternalLinkicon width={10} height={10} fill=\"white\" />\n </a>\n );\n }\n } catch (_) {\n parsedMaybeLink = maybeLinkText;\n }\n return parsedMaybeLink;\n}\n","import { useEffect, useRef, useState } from \"preact/hooks\";\n\nexport type MetaTagInfo = [content: string | null, property: string | null];\n\nconst useHeadObserver = (): React.RefObject<HTMLHeadElement | null> => {\n const [_generation, setGeneration] = useState<number>(0);\n const forceRerender = (): void => setGeneration((old) => ++old);\n const headRef = useRef(document.querySelector(\"head\"));\n\n // useEffect(() => {\n // console.log({ generation });\n // }, [generation]);\n\n useEffect(() => {\n // console.log({ \"headRef.current\": headRef.current });\n if (headRef.current == null) {\n // assume we must have a head by now, and if we don't, we will never get\n // one.\n return;\n }\n const observer = new MutationObserver(forceRerender);\n observer.observe(headRef.current, {\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n return () => observer.disconnect();\n }, []);\n\n return headRef;\n};\n\nexport function useMetaTagInfo(): MetaTagInfo[] {\n const headRef = useHeadObserver();\n const opengraphMetaTags =\n headRef?.current?.querySelectorAll(\"meta[property^='og:']\") ?? [];\n // console.log({\n // opengraphMetaTags: opengraphMetaTags,\n // opengraphMetaTagsLength: opengraphMetaTags.length,\n // });\n return Array.from(opengraphMetaTags).map(\n (tag: Element): MetaTagInfo => [\n tag.getAttribute(\"content\"),\n tag.getAttribute(\"property\"),\n ],\n );\n}\n","import type Preact from \"preact\";\nimport { LinkOrText } from \"./LinkOrText.js\";\nimport { useMetaTagInfo, type MetaTagInfo } from \"../hooks/useMetaTagInfo.js\";\n\nexport function MetaTags(): Preact.JSX.Element {\n const tags = useMetaTagInfo();\n\n return (\n <dl\n data-testid=\"astro-opengraph-toolbar\"\n style={{\n margin: 0,\n display: \"grid\",\n gridTemplateColumns: \"max-content 1fr\",\n gap: 7,\n columnGap: 13,\n }}\n >\n {tags.map((tag) => (\n <MetaTagContent key={tag[1]} tag={tag} />\n ))}\n </dl>\n );\n}\n\nfunction MetaTagContent({ tag }: { tag: MetaTagInfo }): Preact.JSX.Element {\n const [content, property] = tag;\n return (\n <>\n <dt\n style={{\n color: \"white\",\n textAlign: \"right\",\n fontWeight: 500,\n }}\n >\n {property}\n </dt>\n <dd style={{ margin: 0 }}>\n <LinkOrText maybeLinkText={content} />\n </dd>\n </>\n );\n}\n","import type Preact from \"preact\";\nimport { useRef, useEffect } from \"preact/hooks\";\n\nexport function useHoverState<TElement extends HTMLElement>(\n setHoverState: (isHover: boolean) => void,\n): Preact.RefObject<TElement> {\n const ref = useRef<TElement>(null);\n\n useEffect(() => {\n const controller = new AbortController();\n const { signal } = controller;\n ref.current?.addEventListener(\"mouseenter\", () => setHoverState(true), {\n signal,\n });\n ref.current?.addEventListener(\"mouseleave\", () => setHoverState(false), {\n signal,\n });\n\n return () => controller.abort();\n }, [setHoverState]);\n\n return ref;\n}\n","import { useState } from \"preact/hooks\";\n\nexport function useImageURL(): string {\n const imageUrl = useImageURLIfAvailable();\n if (imageUrl == null) {\n throw new Error(\n `Shouldn't be rendering this component without an image URL`,\n );\n }\n return imageUrl;\n}\n\nexport function useImageURLIfAvailable(): string | null {\n const [imageUrlRef] = useState(() => {\n const meta = document.querySelector('meta[property=\"og:image\"]');\n return meta?.getAttribute(\"content\") ?? null;\n });\n return imageUrlRef;\n}\n","import type Preact from \"preact\";\nimport { useImageURL } from \"../hooks/useImageURL.js\";\n\nexport function Image({\n imageSize,\n handleLoadError,\n}: {\n imageSize: number;\n handleLoadError: () => void;\n}): Preact.JSX.Element {\n const imageUrl = useImageURL();\n return (\n <div className=\"image\">\n <a href={imageUrl} target=\"_blank\" title=\"Open image in new tab\">\n <img\n onError={handleLoadError}\n alt=\"Open Graph\"\n src={imageUrl}\n style={{\n maxHeight: \"100%\",\n maxWidth: `${imageSize}%`,\n }}\n />\n </a>\n </div>\n );\n}\n","export function ZoomLabel({ imageSize }: { imageSize: number }): string {\n const formattedNumber = (imageSize / 100).toLocaleString(undefined, {\n minimumFractionDigits: 2,\n });\n return `${formattedNumber}x`;\n}\n","import type Preact from \"preact\";\nimport { ZoomLabel } from \"./ZoomLabel.js\";\n\nexport function ZoomButton({\n value,\n imageSize,\n setImageSize,\n}: {\n value: number;\n imageSize: number;\n setImageSize: (size: number) => void;\n}): Preact.JSX.Element {\n const isSelected = value === imageSize;\n return (\n <astro-dev-toolbar-button\n size=\"small\"\n style={{ padding: 0, margin: 0 }}\n buttonStyle={isSelected ? \"gray\" : \"ghost\"}\n className=\"zoom-button\"\n role=\"radio\"\n onClick={() => setImageSize(value)}\n >\n <ZoomLabel imageSize={value} />\n </astro-dev-toolbar-button>\n );\n}\n","import type { ComponentChildren } from \"preact\";\nimport type Preact from \"preact\";\n\nexport function ToolbarSection({\n icon,\n children,\n}: {\n icon: Preact.JSX.Element;\n children: ComponentChildren;\n}): Preact.JSX.Element {\n return (\n <div\n style={{\n fontSize: 12,\n display: \"flex\",\n alignItems: \"center\",\n columnGap: 5,\n }}\n >\n <div\n style={{\n display: \"inline-block\",\n width: 12,\n height: 12,\n }}\n >\n {icon}\n </div>\n {children}\n </div>\n );\n}\n","import type Preact from \"preact\";\nimport { ZoomButton } from \"./ZoomButton.js\";\nimport { ToolbarSection } from \"./ToolbarSection.js\";\n\nexport function ImageZoomToolbar({\n isHovered,\n imageSize,\n setImageSize,\n}: {\n isHovered: boolean;\n imageSize: number;\n setImageSize: (size: number) => void;\n}): Preact.JSX.Element {\n return (\n <ToolbarSection icon={<astro-dev-toolbar-icon icon=\"gear\" />}>\n {!isHovered ? (\n <ZoomButton\n value={imageSize}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n ) : (\n <>\n <ZoomButton\n value={25}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n <ZoomButton\n value={50}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n <ZoomButton\n value={75}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n <ZoomButton\n value={100}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n </>\n )}\n </ToolbarSection>\n );\n}\n","import { useState, useRef, useEffect, useCallback } from \"preact/hooks\";\nimport type Preact from \"preact\";\nimport type { MouseEventHandler } from \"preact/compat\";\nimport type { DevToolbarButton } from \"astro/runtime/client/dev-toolbar/ui-library/button.js\";\nimport { useImageURL } from \"../hooks/useImageURL.js\";\nimport { ToolbarSection } from \"./ToolbarSection.js\";\n\ntype Timer = ReturnType<typeof setTimeout>;\n\nexport function CopyImageUrlButton(): Preact.JSX.Element {\n const imageUrl = useImageURL();\n const [wasRecentlyClicked, setWasRecentlyClicked] = useState(false);\n const checkTimer = useRef<Timer | null>(null);\n\n useEffect(() => {\n if (wasRecentlyClicked && checkTimer.current == null) {\n checkTimer.current = setTimeout(() => {\n setWasRecentlyClicked(false);\n // TODO investigate\n // eslint-disable-next-line react-compiler/react-compiler\n checkTimer.current = null;\n }, 3_000);\n }\n }, [wasRecentlyClicked]);\n\n const handleClick: MouseEventHandler<DevToolbarButton> = useCallback(\n (evt) => {\n // Copy the text inside the text field\n void navigator.clipboard.writeText(imageUrl);\n setWasRecentlyClicked(true);\n evt.stopPropagation();\n evt.preventDefault();\n },\n [imageUrl],\n );\n\n return (\n <ToolbarSection icon={<astro-dev-toolbar-icon icon=\"copy\" />}>\n <div style={{ display: \"flex\", alignItems: \"center\" }}>\n <astro-dev-toolbar-button\n size=\"small\"\n buttonStyle=\"gray\"\n onClick={handleClick}\n >\n {wasRecentlyClicked ? \"Copied to clipboard\" : \"Copy image URL\"}\n </astro-dev-toolbar-button>\n </div>\n </ToolbarSection>\n );\n}\n","import { Image } from \"./Image.js\";\nimport { ImageZoomToolbar } from \"./ImageZoomToolbar.js\";\nimport { CopyImageUrlButton } from \"./CopyImageUrlButton.js\";\nimport type Preact from \"preact\";\nimport { useState } from \"preact/hooks\";\n\nexport function ImageSection({\n isHovered,\n handleLoadError,\n}: {\n isHovered: boolean;\n handleLoadError: () => void;\n}): Preact.JSX.Element {\n const [imageSize, setImageSize] = useState(100);\n\n return (\n <>\n <Image imageSize={imageSize} handleLoadError={handleLoadError} />\n <div\n data-testid=\"image-section-toolbar\"\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n columnGap: 15,\n }}\n >\n <CopyImageUrlButton />\n <ImageZoomToolbar\n isHovered={isHovered}\n imageSize={imageSize}\n setImageSize={setImageSize}\n />\n </div>\n </>\n );\n}\n","import type { Icon } from \"astro/runtime/client/dev-toolbar/ui-library/icons.js\";\nimport type Preact from \"preact\";\n\nexport function Error({\n message,\n icon,\n}: {\n message: string;\n icon: Icon;\n}): Preact.JSX.Element {\n return (\n <div\n style={{\n display: \"flex\",\n gap: 10,\n alignItems: \"center\",\n }}\n >\n <astro-dev-toolbar-icon style={{ width: 24, height: 24 }} icon={icon} />{\" \"}\n {message}\n </div>\n );\n}\n","export function getRelativeUrl(absoluteUrl: string): string {\n const url = new URL(absoluteUrl);\n return url.pathname;\n}\n","import type Preact from \"preact\";\nimport { useState } from \"preact/hooks\";\nimport { Summary } from \"./Summary.js\";\nimport { MetaTags } from \"./MetaTags.js\";\nimport { useHoverState } from \"../hooks/useHoverState.js\";\nimport { useImageURLIfAvailable } from \"../hooks/useImageURL.js\";\nimport { ImageSection } from \"./ImageSection.js\";\nimport { Error } from \"./Error.js\";\nimport { getRelativeUrl } from \"./getRelativeUrl.js\";\n\nexport function ToolbarApp(): Preact.JSX.Element {\n const [isImageDetailsHovered, setIsImageDetailsHovered] = useState(false);\n const imageDetailsRef = useHoverState<HTMLDetailsElement>(\n setIsImageDetailsHovered,\n );\n const imageUrl = useImageURLIfAvailable();\n const [imageLoadStatus, setImageLoadStatus] = useState<\"pending\" | \"error\">(\n \"pending\",\n );\n\n if (imageUrl == null) {\n return (\n <Error icon=\"warning\" message=\"No Open Graph image found on this page\" />\n );\n } else if (imageLoadStatus === \"error\") {\n return (\n <Error\n icon=\"bug\"\n message={`Error loading image at ${getRelativeUrl(imageUrl)}`}\n />\n );\n }\n\n return (\n <>\n <details open className=\"image\" ref={imageDetailsRef}>\n <Summary>Image</Summary>\n <ImageSection\n isHovered={isImageDetailsHovered}\n handleLoadError={() => setImageLoadStatus(\"error\")}\n />\n </details>\n\n <details>\n <Summary>Meta Tags</Summary>\n <MetaTags />\n </details>\n </>\n );\n}\n","import type Preact from \"preact\";\nimport { styles } from \"../styles.js\";\nimport { ToolbarApp } from \"./ToolbarApp.js\";\n\nexport function ToolbarAppWindow(): Preact.JSX.Element {\n return (\n <astro-dev-toolbar-window>\n <style>{styles}</style>\n <ToolbarApp />\n </astro-dev-toolbar-window>\n );\n}\n","import { render } from \"preact\";\n\nimport { defineToolbarApp } from \"astro/toolbar\";\nimport { ToolbarAppWindow } from \"./components/ToolbarAppWindow.js\";\nimport type { DevToolbarApp } from \"astro\";\n\nconst SESSION_KEY_OPEN = \"@altano/astro-opengraph/toolbar:is-open\";\n\nconst app: DevToolbarApp = defineToolbarApp({\n init(canvas, app) {\n app.onToggled((event) => {\n if (event.state) {\n sessionStorage.setItem(SESSION_KEY_OPEN, \"true\");\n render(<ToolbarAppWindow />, canvas);\n } else {\n sessionStorage.removeItem(SESSION_KEY_OPEN);\n }\n });\n\n app.toggleNotification({\n state: document.querySelector('meta[property=\"og:image\"]') != null,\n level: \"info\",\n });\n\n if (sessionStorage.getItem(SESSION_KEY_OPEN) != null) {\n app.toggleState({ state: true });\n }\n },\n});\n\nexport default app;\n"],"mappings":"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"}
@@ -67,4 +67,4 @@ type OpengraphImageConfigResolved = {
67
67
  };
68
68
  //#endregion
69
69
  export { ComponentMetaTagFallbacks, ImageOptions, ImageOptionsWithFontPaths, OpengraphImageConfig, OpengraphImageConfigDeserialized, OpengraphImageConfigResolved, OpengraphImageConfigSerializableMaybeMocked };
70
- //# sourceMappingURL=types-B1hoqgLx.d.ts.map
70
+ //# sourceMappingURL=types-BGbFKpbi.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@altano/astro-opengraph",
3
- "version": "0.1.1",
3
+ "version": "1.0.1",
4
4
  "description": "Open Graph Tools for Astro",
5
5
  "keywords": [
6
6
  "astro",
@@ -20,7 +20,7 @@
20
20
  "license": "ISC",
21
21
  "author": {
22
22
  "name": "Alan Norbauer",
23
- "email": "altano@gmail.com",
23
+ "email": "alan@norbauer.com",
24
24
  "url": "https://alan.norbauer.com"
25
25
  },
26
26
  "sideEffects": false,
@@ -45,44 +45,44 @@
45
45
  "satori-html": "^0.3.2"
46
46
  },
47
47
  "devDependencies": {
48
- "@astrojs/check": "^0.9.4",
49
- "@astrojs/preact": "^4.0.8",
50
- "@astrojs/svelte": "^7.0.9",
51
- "@astrojs/vue": "^5.0.9",
52
- "@inox-tools/astro-tests": "0.5.1",
53
- "@playwright/test": "1.51.1",
48
+ "@astrojs/check": "^0.9.8",
49
+ "@astrojs/preact": "^5.0.2",
50
+ "@astrojs/svelte": "^8.0.3",
51
+ "@astrojs/vue": "^6.0.1",
52
+ "@inox-tools/astro-tests": "^1.0.0",
53
+ "@playwright/test": "1.58.2",
54
54
  "@types/he": "^1.2.3",
55
- "@types/jest-image-snapshot": "^6.4.0",
56
- "@types/node": "^22.13.10",
57
- "@vitest/coverage-v8": "^3.1.4",
58
- "astro": "^5.10.1",
55
+ "@types/jest-image-snapshot": "^6.4.1",
56
+ "@types/node": "^25.5.0",
57
+ "@vitest/coverage-v8": "^4.1.0",
58
+ "astro": "^6.0.8",
59
59
  "depcheck": "^1.4.7",
60
- "jest-image-snapshot": "^6.4.0",
61
- "preact": "^10.26.5",
62
- "sharp": "^0.33.1",
63
- "svelte": "^5.25.12",
64
- "tsdown": "^0.12.9",
65
- "typescript": "^5.8.2",
66
- "vite": "^6.2.6",
67
- "vitest": "^3.1.4",
68
- "vue": "^3.5.13",
69
- "zx": "^8.5.2",
60
+ "jest-image-snapshot": "^6.5.1",
61
+ "preact": "^10.28.2",
62
+ "sharp": "^0.33.5",
63
+ "svelte": "^5.53.5",
64
+ "tsdown": "^0.21.4",
65
+ "typescript": "^5.9.3",
66
+ "vite": "^7.3.1",
67
+ "vitest": "^4.1.0",
68
+ "vue": "^3.5.27",
69
+ "zx": "^8.8.5",
70
70
  "@altano/assets": "0.0.1",
71
71
  "@altano/build-config": "0.0.1",
72
72
  "@altano/testing": "0.0.1",
73
- "@altano/tiny-async-pool": "4.0.1",
74
73
  "@altano/tsconfig": "0.0.1",
75
- "@altano/vitest-plugins": "1.1.0"
74
+ "@altano/tiny-async-pool": "4.0.2",
75
+ "@altano/vitest-plugins": "1.1.2"
76
76
  },
77
77
  "peerDependencies": {
78
- "astro": "5.x.x",
78
+ "astro": "6.x.x",
79
79
  "preact": ">=10"
80
80
  },
81
81
  "publishConfig": {
82
82
  "access": "public"
83
83
  },
84
84
  "scripts": {
85
- "build": "tsdown",
85
+ "build": "tsdown --config-loader unrun",
86
86
  "check:types:astro": "node --experimental-strip-types ./scripts/check-fixtures.ts",
87
87
  "check:types:src": "tsc --noEmit",
88
88
  "check:types:test": "tsc --noEmit --project ./tests/tsconfig.json",
@@ -93,7 +93,7 @@
93
93
  "lint": "eslint",
94
94
  "lint:fix": "TIMING=1 eslint src/**/*.ts* --fix",
95
95
  "lint:timing": "TIMING=1 eslint src/**/*.ts*",
96
- "test:e2e": "playwright test",
96
+ "test:e2e": "NODE_OPTIONS='--no-experimental-strip-types' playwright test",
97
97
  "test:e2e:server": "astro --root tests/fixtures/ui-frameworks --port 3913 dev",
98
98
  "test:e2e:ui": "playwright test --ui",
99
99
  "test:unit": "vitest --run",
@@ -1,45 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
-
3
- //#region src/config.ts
4
- async function deserializeVirtualConfig(configMaybeMocked) {
5
- const config = typeof configMaybeMocked === "function" ? configMaybeMocked() : configMaybeMocked;
6
- const fontsWithBuffers = await Promise.all(config.imageOptions.fonts.map(async (font) => {
7
- const data = await readFile(font.path);
8
- return {
9
- ...font,
10
- data
11
- };
12
- }));
13
- return {
14
- ...config,
15
- imageOptions: {
16
- ...config.imageOptions,
17
- fonts: fontsWithBuffers
18
- }
19
- };
20
- }
21
- const imageOptionDefaults = {
22
- width: 1200,
23
- height: 630
24
- };
25
- const metaTagDefaults = { "og:image": `/opengraph.png` };
26
- async function getResolvedConfig() {
27
- const module = await import("virtual:astro-opengraph/user-config");
28
- const lazyConfig = module.default;
29
- const deserialized = await deserializeVirtualConfig(lazyConfig);
30
- return {
31
- ...deserialized,
32
- imageOptions: {
33
- ...imageOptionDefaults,
34
- ...deserialized.imageOptions
35
- },
36
- componentMetaTagFallbacks: {
37
- ...deserialized.componentMetaTagFallbacks,
38
- ...metaTagDefaults
39
- }
40
- };
41
- }
42
-
43
- //#endregion
44
- export { deserializeVirtualConfig, getResolvedConfig };
45
- //# sourceMappingURL=config-CzK0JuaO.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-CzK0JuaO.js","names":["configMaybeMocked: OpengraphImageConfigSerializableMaybeMocked","fontsWithBuffers: FontWithBuffer[]","metaTagDefaults: MetaTagDefaults"],"sources":["../src/config.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\n\nimport type {\n FontWithBuffer,\n MetaTagDefaults,\n OpengraphImageConfigDeserialized,\n OpengraphImageConfigResolved,\n OpengraphImageConfigSerializableMaybeMocked,\n} from \"./types.js\";\n\nexport async function deserializeVirtualConfig(\n configMaybeMocked: OpengraphImageConfigSerializableMaybeMocked,\n): Promise<OpengraphImageConfigDeserialized> {\n const config =\n typeof configMaybeMocked === \"function\"\n ? configMaybeMocked() // We're running in vitest which is only capable of mocking functions\n : configMaybeMocked;\n const fontsWithBuffers: FontWithBuffer[] = await Promise.all(\n config.imageOptions.fonts.map(async (font) => {\n const data = await readFile(font.path);\n return {\n ...font,\n data: data,\n };\n }),\n );\n\n return {\n ...config,\n imageOptions: {\n ...config.imageOptions,\n fonts: fontsWithBuffers,\n },\n };\n}\n\nconst imageOptionDefaults = {\n width: 1200,\n height: 630,\n} as const;\n\nconst metaTagDefaults: MetaTagDefaults = {\n \"og:image\": `/opengraph.png`,\n};\n\nexport async function getResolvedConfig(): Promise<OpengraphImageConfigResolved> {\n // Grab the virtual module that holds the integration's user config\n const module = await import(\"virtual:astro-opengraph/user-config\");\n const lazyConfig = module.default;\n const deserialized = await deserializeVirtualConfig(lazyConfig);\n return {\n ...deserialized,\n imageOptions: {\n ...imageOptionDefaults,\n ...deserialized.imageOptions,\n },\n componentMetaTagFallbacks: {\n ...deserialized.componentMetaTagFallbacks,\n ...metaTagDefaults,\n },\n };\n}\n"],"mappings":";;;AAUA,eAAsB,yBACpBA,mBAC2C;CAC3C,MAAM,gBACG,sBAAsB,aACzB,mBAAmB,GACnB;CACN,MAAMC,mBAAqC,MAAM,QAAQ,IACvD,OAAO,aAAa,MAAM,IAAI,OAAO,SAAS;EAC5C,MAAM,OAAO,MAAM,SAAS,KAAK,KAAK;AACtC,SAAO;GACL,GAAG;GACG;EACP;CACF,EAAC,CACH;AAED,QAAO;EACL,GAAG;EACH,cAAc;GACZ,GAAG,OAAO;GACV,OAAO;EACR;CACF;AACF;AAED,MAAM,sBAAsB;CAC1B,OAAO;CACP,QAAQ;AACT;AAED,MAAMC,kBAAmC,EACvC,aAAa,gBACd;AAED,eAAsB,oBAA2D;CAE/E,MAAM,SAAS,MAAM,OAAO;CAC5B,MAAM,aAAa,OAAO;CAC1B,MAAM,eAAe,MAAM,yBAAyB,WAAW;AAC/D,QAAO;EACL,GAAG;EACH,cAAc;GACZ,GAAG;GACH,GAAG,aAAa;EACjB;EACD,2BAA2B;GACzB,GAAG,aAAa;GAChB,GAAG;EACJ;CACF;AACF"}