nuxt-og-image 6.5.3 → 6.7.0

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.
Files changed (108) hide show
  1. package/README.md +2 -0
  2. package/dist/chunks/tw4.cjs +7 -7
  3. package/dist/chunks/tw4.mjs +7 -7
  4. package/dist/chunks/uno.cjs +6 -6
  5. package/dist/chunks/uno.mjs +6 -6
  6. package/dist/cli.cjs +12 -5
  7. package/dist/cli.mjs +10 -3
  8. package/dist/devtools/components/og-image/AddComponentDialog.vue +85 -0
  9. package/dist/devtools/components/og-image/BlueskyCardRenderer.vue +134 -0
  10. package/dist/devtools/components/og-image/CreateOgImageDialog.vue +56 -0
  11. package/dist/devtools/components/og-image/DiscordCardRenderer.vue +125 -0
  12. package/dist/devtools/components/og-image/FacebookCardRenderer.vue +128 -0
  13. package/dist/devtools/components/og-image/IFrameLoader.vue +93 -0
  14. package/dist/devtools/components/og-image/ImageLoader.vue +197 -0
  15. package/dist/devtools/components/og-image/LinkedInCardRenderer.vue +100 -0
  16. package/dist/devtools/components/og-image/RendererSelectModal.vue +356 -0
  17. package/dist/devtools/components/og-image/SlackCardRenderer.vue +140 -0
  18. package/dist/devtools/components/og-image/TemplateComponentPreview.vue +186 -0
  19. package/dist/devtools/components/og-image/TwitterCardRenderer.vue +170 -0
  20. package/dist/devtools/components/og-image/WhatsAppRenderer.vue +294 -0
  21. package/dist/devtools/lib/og-image/keys.ts +8 -0
  22. package/dist/devtools/lib/og-image/og-image.ts +536 -0
  23. package/dist/devtools/lib/og-image/renderer-select.ts +3 -0
  24. package/dist/devtools/lib/og-image/rpc-types.ts +2 -0
  25. package/dist/devtools/lib/og-image/rpc.ts +73 -0
  26. package/dist/devtools/lib/og-image/runtime-types.ts +10 -0
  27. package/dist/devtools/lib/og-image/shared/urlEncoding.ts +502 -0
  28. package/dist/devtools/lib/og-image/shared.ts +30 -0
  29. package/dist/devtools/lib/og-image/templates.ts +9 -0
  30. package/dist/devtools/lib/og-image/types.ts +38 -0
  31. package/dist/devtools/lib/og-image/util/logic.ts +21 -0
  32. package/dist/devtools/nuxt.config.ts +6 -0
  33. package/dist/devtools/pages/og-image/debug.vue +32 -0
  34. package/dist/devtools/pages/og-image/docs.vue +3 -0
  35. package/dist/devtools/pages/og-image/index.vue +1682 -0
  36. package/dist/devtools/pages/og-image/templates.vue +150 -0
  37. package/dist/devtools/pages/og-image.vue +184 -0
  38. package/dist/module.cjs +5 -5
  39. package/dist/module.d.cts +5 -3
  40. package/dist/module.d.mts +5 -3
  41. package/dist/module.d.ts +5 -3
  42. package/dist/module.json +1 -1
  43. package/dist/module.mjs +5 -5
  44. package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.d.ts +1 -1
  45. package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.js +6 -1
  46. package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +13 -6
  47. package/dist/runtime/server/og-image/bindings/font-assets/external-url.d.ts +36 -0
  48. package/dist/runtime/server/og-image/bindings/font-assets/external-url.js +47 -0
  49. package/dist/runtime/server/og-image/bindings/font-assets/node.d.ts +1 -1
  50. package/dist/runtime/server/og-image/bindings/font-assets/node.js +14 -7
  51. package/dist/runtime/server/og-image/bindings/takumi/node-dev.js +7 -1
  52. package/dist/runtime/server/og-image/core/plugins/imageSrc.js +2 -2
  53. package/dist/runtime/server/og-image/fonts.d.ts +4 -0
  54. package/dist/runtime/server/og-image/fonts.js +21 -5
  55. package/dist/runtime/server/og-image/satori/instances.d.ts +1 -2
  56. package/dist/runtime/server/og-image/takumi/renderer.js +61 -19
  57. package/dist/runtime/server/util/ssrf.d.ts +10 -0
  58. package/dist/runtime/server/util/ssrf.js +9 -1
  59. package/dist/runtime/types.d.ts +13 -0
  60. package/dist/shared/{nuxt-og-image.DdbTs-xp.mjs → nuxt-og-image.CPSxZhVO.mjs} +122 -496
  61. package/dist/shared/nuxt-og-image.DM30kcDz.mjs +660 -0
  62. package/dist/shared/nuxt-og-image.RI9DgjgV.cjs +689 -0
  63. package/dist/shared/{nuxt-og-image.CfTPCtaS.cjs → nuxt-og-image.yDJBWXBt.cjs} +181 -555
  64. package/package.json +48 -45
  65. package/dist/devtools/200.html +0 -1
  66. package/dist/devtools/404.html +0 -1
  67. package/dist/devtools/_fonts/4ppnHhMi-pBsWSPo7mY0avYxlDoAg1N3PTzCwXLZ5rA-d9oibkGnTd1JL3tc_xnaVgBLYmOB8kjrK2cvZaqwj9s.woff2 +0 -0
  68. package/dist/devtools/_fonts/PV2hrQG6wq5BlIPDjdL1IcOflycaghyt5MHzlBqZtlo-lb_WexLz3VZqfTN0oi554iBH5tT2j2UFEV-XErCAS3E.woff2 +0 -0
  69. package/dist/devtools/_fonts/VE4cDVCv5MxbFM7ZLoLCGbIpNd71zhp7MDI9lmN5Y7I-xZyDYCUVrd6LV8eVGF3Um3UZjBFuUtDGtvdyTBBRYBo.woff2 +0 -0
  70. package/dist/devtools/_fonts/fVoGbnMbBFd5L9BBp9fUPavUSkZ_EmsQNSyadkT-108-U4T0khaeLQSIhtt9eVvaCEKJjtWJ4ioRJOf8hvqkWY0.woff2 +0 -0
  71. package/dist/devtools/_fonts/lQAxeCEs1R0Lw-H9XRU1RlOARQN8J6npRsPjyEDMe5s-_DUSLEkO3tKTuun_gSnDLoQPVEnpOnyqZMOw0ByZ6PA.woff2 +0 -0
  72. package/dist/devtools/_fonts/lntlqNHKLV2n82yTwMde70QqOjcfLE2XJ5oKZ3vRPWc-z6TxpIZQdWXztWLr9_OFWqt_WJJoeGtuK_-XQMZGQwE.woff2 +0 -0
  73. package/dist/devtools/_nuxt/BZ_CG9ll.js +0 -30
  74. package/dist/devtools/_nuxt/BdMalyEU.js +0 -4
  75. package/dist/devtools/_nuxt/BhkGaWEe.js +0 -3
  76. package/dist/devtools/_nuxt/Bm4Q-nTW.js +0 -3
  77. package/dist/devtools/_nuxt/BsRKQH5X.js +0 -1
  78. package/dist/devtools/_nuxt/C5797Ieg.js +0 -1
  79. package/dist/devtools/_nuxt/CBcJg2GG.js +0 -2
  80. package/dist/devtools/_nuxt/CDaXKRRu.js +0 -1
  81. package/dist/devtools/_nuxt/CM-t-6ZT.js +0 -1
  82. package/dist/devtools/_nuxt/CP0tQR2M.js +0 -1
  83. package/dist/devtools/_nuxt/CXAM78_A.js +0 -1
  84. package/dist/devtools/_nuxt/CYDI7SLa.js +0 -1
  85. package/dist/devtools/_nuxt/CkbDfutK.js +0 -152
  86. package/dist/devtools/_nuxt/Co8Tk_C2.js +0 -1
  87. package/dist/devtools/_nuxt/CqjbkMN9.js +0 -3
  88. package/dist/devtools/_nuxt/D49I50CU.js +0 -1
  89. package/dist/devtools/_nuxt/DevtoolsSection.DkT2bJJh.css +0 -1
  90. package/dist/devtools/_nuxt/DevtoolsSnippet.zV_SDojn.css +0 -1
  91. package/dist/devtools/_nuxt/HWyD49jH.js +0 -1
  92. package/dist/devtools/_nuxt/IFrameLoader.k_861Nnq.css +0 -1
  93. package/dist/devtools/_nuxt/PONEy9N-.js +0 -1
  94. package/dist/devtools/_nuxt/builds/latest.json +0 -1
  95. package/dist/devtools/_nuxt/builds/meta/0f3dbc15-8308-4956-81b9-5507cac7018c.json +0 -1
  96. package/dist/devtools/_nuxt/entry.D7u2asd2.css +0 -2
  97. package/dist/devtools/_nuxt/fira-code.Bc8wnsZt.woff2 +0 -0
  98. package/dist/devtools/_nuxt/hubot-sans.DLGyhQVu.woff2 +0 -0
  99. package/dist/devtools/_nuxt/pO9PmtPW.js +0 -6
  100. package/dist/devtools/_nuxt/pages.0Jk10xlb.css +0 -1
  101. package/dist/devtools/_nuxt/renderer-select.CN5IWe60.css +0 -1
  102. package/dist/devtools/_nuxt/templates.BByln3BG.css +0 -1
  103. package/dist/devtools/debug/index.html +0 -1
  104. package/dist/devtools/docs/index.html +0 -1
  105. package/dist/devtools/index.html +0 -1
  106. package/dist/devtools/templates/index.html +0 -1
  107. package/dist/shared/nuxt-og-image.CJa2KCie.mjs +0 -189
  108. package/dist/shared/nuxt-og-image.CMYbz66P.cjs +0 -193
package/README.md CHANGED
@@ -47,6 +47,8 @@ npx nuxi@latest module add og-image
47
47
  > npx skilld add nuxt-og-image
48
48
  > ```
49
49
 
50
+ 💡 Built your OG images? Check how they render across Twitter, Facebook, LinkedIn and Slack with the free [Social Share Debugger](https://nuxtseo.com/tools/social-share-debugger), or monitor them site-wide with [Nuxt SEO Pro](https://nuxtseo.com/pro).
51
+
50
52
  ## Documentation
51
53
 
52
54
  [📖 Read the full documentation](https://nuxtseo.com/og-image/getting-started/installation) for more information.
@@ -4,7 +4,8 @@ const promises = require('node:fs/promises');
4
4
  const node_url = require('node:url');
5
5
  const exsolve = require('exsolve');
6
6
  const pathe = require('pathe');
7
- const module$1 = require('../shared/nuxt-og-image.CfTPCtaS.cjs');
7
+ const module$1 = require('../shared/nuxt-og-image.yDJBWXBt.cjs');
8
+ require('node:crypto');
8
9
  require('node:fs');
9
10
  require('@nuxt/kit');
10
11
  require('defu');
@@ -12,12 +13,14 @@ require('nuxt-site-config/kit');
12
13
  require('ohash');
13
14
  require('pkg-types');
14
15
  require('std-env');
15
- require('node:crypto');
16
16
  require('oxc-walker');
17
- require('nuxtseo-shared/kit');
17
+ require('../shared/nuxt-og-image.RI9DgjgV.cjs');
18
+ require('magicast');
19
+ require('magicast/helpers');
18
20
  require('../../dist/runtime/logger.js');
19
- require('chrome-launcher');
20
21
  require('nypm');
22
+ require('nuxtseo-shared/kit');
23
+ require('chrome-launcher');
21
24
  require('nuxtseo-shared/devtools');
22
25
  require('unstorage');
23
26
  require('unstorage/drivers/fs-lite');
@@ -30,9 +33,6 @@ require('@vue/compiler-sfc');
30
33
  require('ofetch');
31
34
  require('ultrahtml');
32
35
  require('../../dist/runtime/server/og-image/core/transforms/emojis/emoji-utils.js');
33
- require('../shared/nuxt-og-image.CMYbz66P.cjs');
34
- require('magicast');
35
- require('magicast/helpers');
36
36
 
37
37
  const RE_GRADIENT_STOP_PREFIX = /^(from|via|to)-/;
38
38
  const RE_COLOR_SHADE = /^(.+)-(\d+)$/;
@@ -2,7 +2,8 @@ import { readFile } from 'node:fs/promises';
2
2
  import { pathToFileURL } from 'node:url';
3
3
  import { resolveModulePath } from 'exsolve';
4
4
  import { dirname, join } from 'pathe';
5
- import { e as extractVariantBaseClasses, r as resolveVariantPrefixes, h as resolveExtractedVars, i as resolveVarsDeep, s as simplifyCss, p as postProcessStyles, l as loadLightningCss, a as extractCssVars, c as extractUniversalVars, d as extractPerClassVars, g as extractVarsFromCss, f as extractClassStyles } from '../shared/nuxt-og-image.DdbTs-xp.mjs';
5
+ import { e as extractVariantBaseClasses, r as resolveVariantPrefixes, h as resolveExtractedVars, i as resolveVarsDeep, s as simplifyCss, p as postProcessStyles, l as loadLightningCss, a as extractCssVars, c as extractUniversalVars, d as extractPerClassVars, g as extractVarsFromCss, f as extractClassStyles } from '../shared/nuxt-og-image.CPSxZhVO.mjs';
6
+ import 'node:crypto';
6
7
  import 'node:fs';
7
8
  import '@nuxt/kit';
8
9
  import 'defu';
@@ -10,12 +11,14 @@ import 'nuxt-site-config/kit';
10
11
  import 'ohash';
11
12
  import 'pkg-types';
12
13
  import 'std-env';
13
- import 'node:crypto';
14
14
  import 'oxc-walker';
15
- import 'nuxtseo-shared/kit';
15
+ import '../shared/nuxt-og-image.DM30kcDz.mjs';
16
+ import 'magicast';
17
+ import 'magicast/helpers';
16
18
  import '../../dist/runtime/logger.js';
17
- import 'chrome-launcher';
18
19
  import 'nypm';
20
+ import 'nuxtseo-shared/kit';
21
+ import 'chrome-launcher';
19
22
  import 'nuxtseo-shared/devtools';
20
23
  import 'unstorage';
21
24
  import 'unstorage/drivers/fs-lite';
@@ -28,9 +31,6 @@ import '@vue/compiler-sfc';
28
31
  import 'ofetch';
29
32
  import 'ultrahtml';
30
33
  import '../../dist/runtime/server/og-image/core/transforms/emojis/emoji-utils.js';
31
- import '../shared/nuxt-og-image.CJa2KCie.mjs';
32
- import 'magicast';
33
- import 'magicast/helpers';
34
34
 
35
35
  const RE_GRADIENT_STOP_PREFIX = /^(from|via|to)-/;
36
36
  const RE_COLOR_SHADE = /^(.+)-(\d+)$/;
@@ -3,7 +3,8 @@
3
3
  const promises = require('node:fs/promises');
4
4
  const defu = require('defu');
5
5
  const logger_js = require('../../dist/runtime/logger.js');
6
- const module$1 = require('../shared/nuxt-og-image.CfTPCtaS.cjs');
6
+ const module$1 = require('../shared/nuxt-og-image.yDJBWXBt.cjs');
7
+ require('node:crypto');
7
8
  require('node:fs');
8
9
  require('node:url');
9
10
  require('@nuxt/kit');
@@ -12,11 +13,13 @@ require('ohash');
12
13
  require('pathe');
13
14
  require('pkg-types');
14
15
  require('std-env');
15
- require('node:crypto');
16
16
  require('oxc-walker');
17
+ require('../shared/nuxt-og-image.RI9DgjgV.cjs');
18
+ require('magicast');
19
+ require('magicast/helpers');
20
+ require('nypm');
17
21
  require('nuxtseo-shared/kit');
18
22
  require('chrome-launcher');
19
- require('nypm');
20
23
  require('nuxtseo-shared/devtools');
21
24
  require('unstorage');
22
25
  require('unstorage/drivers/fs-lite');
@@ -30,9 +33,6 @@ require('ofetch');
30
33
  require('ultrahtml');
31
34
  require('../../dist/runtime/server/og-image/core/transforms/emojis/emoji-utils.js');
32
35
  require('exsolve');
33
- require('../shared/nuxt-og-image.CMYbz66P.cjs');
34
- require('magicast');
35
- require('magicast/helpers');
36
36
 
37
37
  const RE_SVG_DATA_URL = /url\("data:image\/svg\+xml[;,]([^"]+)"\)/;
38
38
  const RE_UTF8_PREFIX = /^utf8,/;
@@ -1,7 +1,8 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { defu } from 'defu';
3
3
  import { logger } from '../../dist/runtime/logger.js';
4
- import { e as extractVariantBaseClasses, s as simplifyCss, a as extractCssVars, b as extractPropertyInitialValues, c as extractUniversalVars, d as extractPerClassVars, f as extractClassStyles, p as postProcessStyles, r as resolveVariantPrefixes, g as extractVarsFromCss, h as resolveExtractedVars } from '../shared/nuxt-og-image.DdbTs-xp.mjs';
4
+ import { e as extractVariantBaseClasses, s as simplifyCss, a as extractCssVars, b as extractPropertyInitialValues, c as extractUniversalVars, d as extractPerClassVars, f as extractClassStyles, p as postProcessStyles, r as resolveVariantPrefixes, g as extractVarsFromCss, h as resolveExtractedVars } from '../shared/nuxt-og-image.CPSxZhVO.mjs';
5
+ import 'node:crypto';
5
6
  import 'node:fs';
6
7
  import 'node:url';
7
8
  import '@nuxt/kit';
@@ -10,11 +11,13 @@ import 'ohash';
10
11
  import 'pathe';
11
12
  import 'pkg-types';
12
13
  import 'std-env';
13
- import 'node:crypto';
14
14
  import 'oxc-walker';
15
+ import '../shared/nuxt-og-image.DM30kcDz.mjs';
16
+ import 'magicast';
17
+ import 'magicast/helpers';
18
+ import 'nypm';
15
19
  import 'nuxtseo-shared/kit';
16
20
  import 'chrome-launcher';
17
- import 'nypm';
18
21
  import 'nuxtseo-shared/devtools';
19
22
  import 'unstorage';
20
23
  import 'unstorage/drivers/fs-lite';
@@ -28,9 +31,6 @@ import 'ofetch';
28
31
  import 'ultrahtml';
29
32
  import '../../dist/runtime/server/og-image/core/transforms/emojis/emoji-utils.js';
30
33
  import 'exsolve';
31
- import '../shared/nuxt-og-image.CJa2KCie.mjs';
32
- import 'magicast';
33
- import 'magicast/helpers';
34
34
 
35
35
  const RE_SVG_DATA_URL = /url\("data:image\/svg\+xml[;,]([^"]+)"\)/;
36
36
  const RE_UTF8_PREFIX = /^utf8,/;
package/dist/cli.cjs CHANGED
@@ -10,10 +10,14 @@ const nypm = require('nypm');
10
10
  const oxcWalker = require('oxc-walker');
11
11
  const pathe = require('pathe');
12
12
  const ultrahtml = require('ultrahtml');
13
- const fonts = require('./shared/nuxt-og-image.CMYbz66P.cjs');
13
+ const dependencies = require('./shared/nuxt-og-image.RI9DgjgV.cjs');
14
14
  require('magicast');
15
15
  require('magicast/helpers');
16
16
  require('../dist/runtime/logger.js');
17
+ require('std-env');
18
+ require('defu');
19
+ require('nuxtseo-shared/kit');
20
+ require('chrome-launcher');
17
21
 
18
22
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
19
23
  function _interopNamespaceCompat(e) {
@@ -189,11 +193,14 @@ const RENDERERS = [
189
193
  }
190
194
  ];
191
195
  const EDGE_PRESETS = ["cloudflare", "cloudflare-pages", "cloudflare-module", "vercel-edge", "netlify-edge"];
192
- function getRendererDeps(renderer, isEdge) {
196
+ function getRendererDeps(renderer, isEdge, options = {}) {
193
197
  switch (renderer) {
194
198
  case "satori":
195
199
  return isEdge ? ["satori", "@resvg/resvg-js", "@resvg/resvg-wasm"] : ["satori", "@resvg/resvg-js"];
196
200
  case "takumi":
201
+ if (options.installSpec) {
202
+ return isEdge ? [dependencies.TAKUMI_CORE_INSTALL_SPEC, dependencies.TAKUMI_WASM_INSTALL_SPEC] : [dependencies.TAKUMI_CORE_INSTALL_SPEC];
203
+ }
197
204
  return isEdge ? ["@takumi-rs/core", "@takumi-rs/wasm"] : ["@takumi-rs/core"];
198
205
  case "browser":
199
206
  return isEdge ? [] : ["playwright-core"];
@@ -554,7 +561,7 @@ async function installRendererDeps(renderers, isEdge) {
554
561
  const pmName = pm?.name || "npm";
555
562
  const allDeps = [];
556
563
  for (const renderer of renderers) {
557
- allDeps.push(...getRendererDeps(renderer, isEdge));
564
+ allDeps.push(...getRendererDeps(renderer, isEdge, { installSpec: true }));
558
565
  }
559
566
  const uniqueDeps = [...new Set(allDeps)];
560
567
  if (uniqueDeps.length === 0)
@@ -706,7 +713,7 @@ async function runMigrate(args2) {
706
713
  if (dryRun) {
707
714
  p__namespace.log.info(`Would remove defaults.component: '${migrationCheck.defaultComponentName}'`);
708
715
  } else {
709
- const result = await fonts.migrateDefaultsComponent(cwd).catch((err) => {
716
+ const result = await dependencies.migrateDefaultsComponent(cwd).catch((err) => {
710
717
  p__namespace.log.warn(`Failed to migrate defaults.component: ${err.message}`);
711
718
  return { migrated: false, componentName: null, message: err.message };
712
719
  });
@@ -720,7 +727,7 @@ async function runMigrate(args2) {
720
727
  if (dryRun) {
721
728
  p__namespace.log.info("Would migrate ogImage.fonts to @nuxt/fonts config");
722
729
  } else {
723
- const result = await fonts.migrateFontsConfig(cwd).catch((err) => {
730
+ const result = await dependencies.migrateFontsConfig(cwd).catch((err) => {
724
731
  p__namespace.log.warn(`Failed to migrate fonts config: ${err.message}`);
725
732
  return { migrated: false, message: err.message };
726
733
  });
package/dist/cli.mjs CHANGED
@@ -8,10 +8,14 @@ import { detectPackageManager, removeDependency, addDependency } from 'nypm';
8
8
  import { parseAndWalk } from 'oxc-walker';
9
9
  import { dirname, resolve, join, relative, basename } from 'pathe';
10
10
  import { parse, walkSync, ELEMENT_NODE } from 'ultrahtml';
11
- import { m as migrateDefaultsComponent, a as migrateFontsConfig } from './shared/nuxt-og-image.CJa2KCie.mjs';
11
+ import { m as migrateDefaultsComponent, a as migrateFontsConfig, T as TAKUMI_CORE_INSTALL_SPEC, b as TAKUMI_WASM_INSTALL_SPEC } from './shared/nuxt-og-image.DM30kcDz.mjs';
12
12
  import 'magicast';
13
13
  import 'magicast/helpers';
14
14
  import '../dist/runtime/logger.js';
15
+ import 'std-env';
16
+ import 'defu';
17
+ import 'nuxtseo-shared/kit';
18
+ import 'chrome-launcher';
15
19
 
16
20
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
17
21
  const communityDir = resolve(__dirname$1, "runtime/app/components/Templates/Community");
@@ -172,11 +176,14 @@ const RENDERERS = [
172
176
  }
173
177
  ];
174
178
  const EDGE_PRESETS = ["cloudflare", "cloudflare-pages", "cloudflare-module", "vercel-edge", "netlify-edge"];
175
- function getRendererDeps(renderer, isEdge) {
179
+ function getRendererDeps(renderer, isEdge, options = {}) {
176
180
  switch (renderer) {
177
181
  case "satori":
178
182
  return isEdge ? ["satori", "@resvg/resvg-js", "@resvg/resvg-wasm"] : ["satori", "@resvg/resvg-js"];
179
183
  case "takumi":
184
+ if (options.installSpec) {
185
+ return isEdge ? [TAKUMI_CORE_INSTALL_SPEC, TAKUMI_WASM_INSTALL_SPEC] : [TAKUMI_CORE_INSTALL_SPEC];
186
+ }
180
187
  return isEdge ? ["@takumi-rs/core", "@takumi-rs/wasm"] : ["@takumi-rs/core"];
181
188
  case "browser":
182
189
  return isEdge ? [] : ["playwright-core"];
@@ -537,7 +544,7 @@ async function installRendererDeps(renderers, isEdge) {
537
544
  const pmName = pm?.name || "npm";
538
545
  const allDeps = [];
539
546
  for (const renderer of renderers) {
540
- allDeps.push(...getRendererDeps(renderer, isEdge));
547
+ allDeps.push(...getRendererDeps(renderer, isEdge, { installSpec: true }));
541
548
  }
542
549
  const uniqueDeps = [...new Set(allDeps)];
543
550
  if (uniqueDeps.length === 0)
@@ -0,0 +1,85 @@
1
+ <script setup lang="ts">
2
+ import type { AddComponentResult } from '../../lib/og-image/templates'
3
+ import { computed, ref, watch } from 'vue'
4
+ import { AddComponentDialogPromise } from '../../lib/og-image/templates'
5
+
6
+ function handleClose(_a: unknown, resolve: (value: AddComponentResult | false) => void) {
7
+ resolve(false)
8
+ }
9
+
10
+ const RE_WORD_CHARS_ONLY = /^\w+$/
11
+
12
+ const componentName = ref('')
13
+ const nameError = ref('')
14
+
15
+ function validateName(value: string): string {
16
+ if (!value.trim())
17
+ return 'Name is required'
18
+ if (!RE_WORD_CHARS_ONLY.test(value.trim()))
19
+ return 'Only letters, numbers, and underscores allowed'
20
+ return ''
21
+ }
22
+
23
+ watch(componentName, (v) => {
24
+ nameError.value = v ? validateName(v) : ''
25
+ })
26
+
27
+ const previewName = computed(() => {
28
+ const name = componentName.value.trim()
29
+ if (!name)
30
+ return ''
31
+ return name.charAt(0).toUpperCase() + name.slice(1)
32
+ })
33
+
34
+ function submit(resolve: (value: AddComponentResult | false) => void) {
35
+ const name = componentName.value.trim()
36
+ const error = validateName(name)
37
+ if (error) {
38
+ nameError.value = error
39
+ return
40
+ }
41
+ resolve({ name: name.charAt(0).toUpperCase() + name.slice(1) })
42
+ componentName.value = ''
43
+ nameError.value = ''
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <AddComponentDialogPromise v-slot="{ resolve }">
49
+ <UModal
50
+ :open="true"
51
+ title="Create OG Image Component"
52
+ @update:open="handleClose('a', resolve)"
53
+ @close="handleClose('b', resolve)"
54
+ >
55
+ <template #body>
56
+ <div class="flex flex-col gap-4">
57
+ <UFormField label="Component Name" :error="nameError" hint="Auto-capitalized to PascalCase">
58
+ <UInput
59
+ v-model="componentName"
60
+ placeholder="MyOgImage"
61
+ autofocus
62
+ class="w-full"
63
+ @keydown.enter="submit(resolve)"
64
+ />
65
+ </UFormField>
66
+
67
+ <div v-if="previewName" class="text-xs text-[var(--color-text-subtle)] font-mono bg-[var(--color-surface-sunken)] rounded-lg px-3 py-2">
68
+ defineOgImage('{{ previewName }}')
69
+ </div>
70
+ </div>
71
+ </template>
72
+
73
+ <template #footer>
74
+ <div class="flex justify-end gap-3">
75
+ <UButton variant="ghost" color="neutral" @click="resolve(false)">
76
+ Cancel
77
+ </UButton>
78
+ <UButton color="primary" :disabled="!componentName.trim() || !!nameError" @click="submit(resolve)">
79
+ Create
80
+ </UButton>
81
+ </div>
82
+ </template>
83
+ </UModal>
84
+ </AddComponentDialogPromise>
85
+ </template>
@@ -0,0 +1,134 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <div class="bluesky-card">
6
+ <div class="bluesky-image">
7
+ <slot />
8
+ <div class="bluesky-image-overlay" />
9
+ </div>
10
+ <div class="bluesky-content">
11
+ <p class="bluesky-title">
12
+ <slot name="title" />
13
+ </p>
14
+ <p class="bluesky-description">
15
+ <slot name="description" />
16
+ </p>
17
+ <div class="bluesky-domain">
18
+ <svg class="bluesky-globe" viewBox="0 0 16 16" fill="none">
19
+ <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="1.3" />
20
+ <ellipse cx="8" cy="8" rx="3.5" ry="7" stroke="currentColor" stroke-width="1.3" />
21
+ <line x1="1.5" y1="5.5" x2="14.5" y2="5.5" stroke="currentColor" stroke-width="1.3" />
22
+ <line x1="1.5" y1="10.5" x2="14.5" y2="10.5" stroke="currentColor" stroke-width="1.3" />
23
+ </svg>
24
+ <slot name="siteName" />
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </template>
29
+
30
+ <style>
31
+ .bluesky-card {
32
+ width: 100%;
33
+ max-width: 513px;
34
+ margin: 0 auto;
35
+ border-radius: 12px;
36
+ overflow: hidden;
37
+ border: 1px solid oklch(88% 0.01 260);
38
+ background: oklch(100% 0 0);
39
+ box-shadow: 0 4px 24px oklch(0% 0 0 / 0.08);
40
+ font-family: 'Hubot Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
41
+ }
42
+
43
+ .dark .bluesky-card {
44
+ background: #171d27;
45
+ border-color: rgb(44, 58, 78);
46
+ box-shadow: 0 4px 24px oklch(0% 0 0 / 0.25);
47
+ }
48
+
49
+ .bluesky-image {
50
+ aspect-ratio: 2 / 1;
51
+ width: 100%;
52
+ position: relative;
53
+ overflow: hidden;
54
+ background: oklch(96% 0.01 260);
55
+ }
56
+
57
+ .dark .bluesky-image {
58
+ background: oklch(22% 0.02 260);
59
+ }
60
+
61
+ .bluesky-image img,
62
+ .bluesky-image > *:first-child:not(.bluesky-image-overlay) {
63
+ width: 100%;
64
+ height: 100%;
65
+ object-fit: cover;
66
+ }
67
+
68
+ .bluesky-image-overlay {
69
+ position: absolute;
70
+ inset: 0;
71
+ box-shadow: inset 0 0 0 1px oklch(0% 0 0 / 0.05);
72
+ pointer-events: none;
73
+ }
74
+
75
+ .dark .bluesky-image-overlay {
76
+ box-shadow: inset 0 0 0 1px oklch(100% 0 0 / 0.05);
77
+ }
78
+
79
+ .bluesky-content {
80
+ padding: 12px 14px;
81
+ }
82
+
83
+ .bluesky-title {
84
+ font-size: 15px;
85
+ font-weight: 600;
86
+ color: oklch(15% 0.02 260);
87
+ margin: 0 0 2px;
88
+ line-height: 1.35;
89
+ display: -webkit-box;
90
+ -webkit-line-clamp: 2;
91
+ -webkit-box-orient: vertical;
92
+ overflow: hidden;
93
+ }
94
+
95
+ .dark .bluesky-title {
96
+ color: oklch(95% 0.01 260);
97
+ }
98
+
99
+ .bluesky-description {
100
+ font-size: 13px;
101
+ color: oklch(50% 0.02 260);
102
+ margin: 0 0 8px;
103
+ line-height: 1.4;
104
+ display: -webkit-box;
105
+ -webkit-line-clamp: 2;
106
+ -webkit-box-orient: vertical;
107
+ overflow: hidden;
108
+ }
109
+
110
+ .dark .bluesky-description {
111
+ color: oklch(65% 0.02 260);
112
+ }
113
+
114
+ .bluesky-domain {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 4px;
118
+ font-size: 11.3px;
119
+ letter-spacing: 0px;
120
+ color: rgb(171, 184, 201);
121
+ padding-top: 8px;
122
+ border-top: 1px solid oklch(92% 0.01 260);
123
+ }
124
+
125
+ .dark .bluesky-domain {
126
+ border-top-color: oklch(28% 0.02 260);
127
+ }
128
+
129
+ .bluesky-globe {
130
+ width: 13px;
131
+ height: 13px;
132
+ flex-shrink: 0;
133
+ }
134
+ </style>
@@ -0,0 +1,56 @@
1
+ <script setup lang="ts">
2
+ import type { Ref } from 'vue'
3
+ import type { GlobalDebugResponse } from '../../lib/og-image/types'
4
+ import { computed, ref, watch } from 'vue'
5
+ import { inject } from '#imports'
6
+ import { GlobalDebugKey } from '../../lib/og-image/keys'
7
+ import { CreateOgImageDialogPromise } from '../../lib/og-image/templates'
8
+
9
+ function handleClose(_a: unknown, resolve: (value: string | false) => void) {
10
+ resolve(false)
11
+ }
12
+
13
+ const globalDebug = inject(GlobalDebugKey) as Ref<GlobalDebugResponse | null>
14
+
15
+ const componentDirs = computed(() => globalDebug.value?.runtimeConfig?.componentDirs || [])
16
+ const selected = ref(componentDirs.value[0])
17
+ watch(componentDirs, (dirs) => {
18
+ if (!selected.value && dirs.length > 0)
19
+ selected.value = dirs[0]
20
+ })
21
+ </script>
22
+
23
+ <template>
24
+ <CreateOgImageDialogPromise v-slot="{ resolve, args }">
25
+ <UModal
26
+ :open="true"
27
+ title="Eject Component"
28
+ description="Copy a community template to an OG Image component directory in your project. You can configure directories using componentDirs in nuxt.config."
29
+ @update:open="handleClose('a', resolve)"
30
+ @close="handleClose('b', resolve)"
31
+ >
32
+ <template #body>
33
+ <URadioGroup
34
+ v-model="selected"
35
+ :items="componentDirs.map((dir: string) => ({
36
+ label: `./components/${dir}/${args[0]}.vue`,
37
+ value: dir,
38
+ }))"
39
+ variant="card"
40
+ legend="Choose Output Path"
41
+ />
42
+ </template>
43
+
44
+ <template #footer>
45
+ <div class="flex justify-end gap-3">
46
+ <UButton variant="ghost" color="neutral" @click="resolve(false)">
47
+ Cancel
48
+ </UButton>
49
+ <UButton color="primary" @click="resolve(selected || false)">
50
+ Create Component
51
+ </UButton>
52
+ </div>
53
+ </template>
54
+ </UModal>
55
+ </CreateOgImageDialogPromise>
56
+ </template>
@@ -0,0 +1,125 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <div class="discord-card">
6
+ <div class="discord-body">
7
+ <div class="discord-sitename">
8
+ <slot name="siteName" />
9
+ </div>
10
+ <div class="discord-title">
11
+ <slot name="title" />
12
+ </div>
13
+ <div class="discord-description">
14
+ <slot name="description" />
15
+ </div>
16
+ <div class="discord-image">
17
+ <slot />
18
+ <div class="discord-image-overlay" />
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </template>
23
+
24
+ <style>
25
+ .discord-card {
26
+ display: flex;
27
+ max-width: 432px;
28
+ margin: 0 auto;
29
+ border-radius: 8px;
30
+ border: 1px solid #e3e5e8;
31
+ border-left: 4px solid #e3e5e8;
32
+ background: #f2f3f5;
33
+ overflow: hidden;
34
+ font-family: 'gg sans', 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
35
+ }
36
+
37
+ .dark .discord-card {
38
+ background: #2b2d31;
39
+ border-color: #232428;
40
+ border-left-color: #1e1f22;
41
+ }
42
+
43
+ .discord-body {
44
+ flex: 1;
45
+ min-width: 0;
46
+ padding: 8px 16px 16px 12px;
47
+ }
48
+
49
+ .discord-sitename {
50
+ font-size: 12px;
51
+ font-weight: 400;
52
+ color: #4e5058;
53
+ margin-bottom: 2px;
54
+ line-height: 16px;
55
+ }
56
+
57
+ .dark .discord-sitename {
58
+ color: #b5bac1;
59
+ }
60
+
61
+ .discord-title {
62
+ font-size: 16px;
63
+ font-weight: 700;
64
+ color: #006ce7;
65
+ cursor: pointer;
66
+ margin-bottom: 4px;
67
+ line-height: 22px;
68
+ display: -webkit-box;
69
+ -webkit-line-clamp: 2;
70
+ -webkit-box-orient: vertical;
71
+ overflow: hidden;
72
+ }
73
+
74
+ .dark .discord-title {
75
+ color: #00a8fc;
76
+ }
77
+
78
+ .discord-title:hover {
79
+ text-decoration: underline;
80
+ }
81
+
82
+ .discord-description {
83
+ font-size: 14px;
84
+ color: #313338;
85
+ line-height: 18px;
86
+ margin-bottom: 16px;
87
+ display: -webkit-box;
88
+ -webkit-line-clamp: 3;
89
+ -webkit-box-orient: vertical;
90
+ overflow: hidden;
91
+ white-space: pre-wrap;
92
+ }
93
+
94
+ .dark .discord-description {
95
+ color: #dbdee1;
96
+ }
97
+
98
+ .discord-image {
99
+ border-radius: 4px;
100
+ overflow: hidden;
101
+ position: relative;
102
+ max-width: 400px;
103
+ max-height: 300px;
104
+ }
105
+
106
+ .discord-image img,
107
+ .discord-image > *:first-child:not(.discord-image-overlay) {
108
+ max-width: 100%;
109
+ max-height: 300px;
110
+ border-radius: 4px;
111
+ display: block;
112
+ }
113
+
114
+ .discord-image-overlay {
115
+ position: absolute;
116
+ inset: 0;
117
+ box-shadow: inset 0 0 0 1px oklch(0% 0 0 / 0.04);
118
+ border-radius: 4px;
119
+ pointer-events: none;
120
+ }
121
+
122
+ .dark .discord-image-overlay {
123
+ box-shadow: inset 0 0 0 1px oklch(100% 0 0 / 0.06);
124
+ }
125
+ </style>