@moku-labs/web 1.5.0 → 1.5.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/index.cjs +79 -2
- package/dist/index.d.cts +7 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +79 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4174,6 +4174,45 @@ function defaultCard(input) {
|
|
|
4174
4174
|
} }, input.title);
|
|
4175
4175
|
}
|
|
4176
4176
|
/**
|
|
4177
|
+
* The built-in SITE-LEVEL default card — the site name over its description on a dark
|
|
4178
|
+
* background, centered. Rendered once (when `ogImage.defaultCard` is true) to `og-default.png`
|
|
4179
|
+
* and used as the `head.defaultOgImage` fallback. Reads `siteName` + `description` from the
|
|
4180
|
+
* {@link RichOgInput}; the per-article `render` hook is deliberately NOT applied here.
|
|
4181
|
+
*
|
|
4182
|
+
* @param input - The rich OG input (only `siteName` + `description` are used).
|
|
4183
|
+
* @returns The Preact `VNode` for the site default card.
|
|
4184
|
+
* @example
|
|
4185
|
+
* ```ts
|
|
4186
|
+
* defaultSiteCard({ ...input, siteName: "My Blog", description: "A dev blog" });
|
|
4187
|
+
* ```
|
|
4188
|
+
*/
|
|
4189
|
+
function defaultSiteCard(input) {
|
|
4190
|
+
const children = [(0, preact.h)("div", { style: {
|
|
4191
|
+
display: "flex",
|
|
4192
|
+
fontSize: 72,
|
|
4193
|
+
fontWeight: 700,
|
|
4194
|
+
color: "#ffffff"
|
|
4195
|
+
} }, input.siteName)];
|
|
4196
|
+
if (input.description) children.push((0, preact.h)("div", { style: {
|
|
4197
|
+
display: "flex",
|
|
4198
|
+
marginTop: 28,
|
|
4199
|
+
maxWidth: 900,
|
|
4200
|
+
fontSize: 32,
|
|
4201
|
+
color: "#a1a1aa",
|
|
4202
|
+
textAlign: "center"
|
|
4203
|
+
} }, input.description));
|
|
4204
|
+
return (0, preact.h)("div", { style: {
|
|
4205
|
+
display: "flex",
|
|
4206
|
+
flexDirection: "column",
|
|
4207
|
+
width: "100%",
|
|
4208
|
+
height: "100%",
|
|
4209
|
+
alignItems: "center",
|
|
4210
|
+
justifyContent: "center",
|
|
4211
|
+
padding: 80,
|
|
4212
|
+
background: "#0b0b0c"
|
|
4213
|
+
} }, ...children);
|
|
4214
|
+
}
|
|
4215
|
+
/**
|
|
4177
4216
|
* The default PNG renderer: a Preact `VNode` (custom `render` hook or the built-in
|
|
4178
4217
|
* card) is rendered to SVG by Satori, then rasterized to PNG by resvg. Both native
|
|
4179
4218
|
* deps are imported LAZILY (browser-safe goal); the VNode→Satori-input cast happens
|
|
@@ -4263,6 +4302,24 @@ function resolveSiteName(ctx) {
|
|
|
4263
4302
|
}
|
|
4264
4303
|
}
|
|
4265
4304
|
/**
|
|
4305
|
+
* Resolve the site description via `ctx.require(sitePlugin)`, falling back to `""` when the
|
|
4306
|
+
* site API is unavailable (e.g. unit mocks that omit it). Used by the site default card.
|
|
4307
|
+
*
|
|
4308
|
+
* @param ctx - Plugin context (provides `require`).
|
|
4309
|
+
* @returns The site description, or `""` when the site plugin is not wired.
|
|
4310
|
+
* @example
|
|
4311
|
+
* ```ts
|
|
4312
|
+
* resolveSiteDescription(ctx);
|
|
4313
|
+
* ```
|
|
4314
|
+
*/
|
|
4315
|
+
function resolveSiteDescription(ctx) {
|
|
4316
|
+
try {
|
|
4317
|
+
return ctx.require(sitePlugin).description();
|
|
4318
|
+
} catch {
|
|
4319
|
+
return "";
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
/**
|
|
4266
4323
|
* Render (or cache-skip) one article's OG image, mutating {@link RenderTally} in
|
|
4267
4324
|
* place. A matching cached hash bumps `skipped` and returns early; otherwise the
|
|
4268
4325
|
* PNG is rasterized to `<outDir>/og/<slug>.png`, the cache entry is updated, and
|
|
@@ -4333,6 +4390,10 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4333
4390
|
fonts,
|
|
4334
4391
|
...renderHook
|
|
4335
4392
|
});
|
|
4393
|
+
const renderSitePng = options.renderPng ?? makeDefaultRenderer({
|
|
4394
|
+
fonts,
|
|
4395
|
+
render: defaultSiteCard
|
|
4396
|
+
});
|
|
4336
4397
|
const siteName = resolveSiteName(ctx);
|
|
4337
4398
|
const defaultLocale = ctx.require(i18nPlugin).defaultLocale();
|
|
4338
4399
|
const articles = selectArticles(readCachedContent(ctx), defaultLocale);
|
|
@@ -4357,15 +4418,31 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4357
4418
|
outDir
|
|
4358
4419
|
}, tally);
|
|
4359
4420
|
})));
|
|
4421
|
+
const defaultCard = config.defaultCard === true;
|
|
4422
|
+
if (defaultCard) {
|
|
4423
|
+
const png = await renderSitePng({
|
|
4424
|
+
title: siteName,
|
|
4425
|
+
description: resolveSiteDescription(ctx),
|
|
4426
|
+
date: "",
|
|
4427
|
+
tags: [],
|
|
4428
|
+
locale: defaultLocale,
|
|
4429
|
+
siteName,
|
|
4430
|
+
size
|
|
4431
|
+
});
|
|
4432
|
+
await (0, node_fs_promises.mkdir)(ctx.config.outDir, { recursive: true });
|
|
4433
|
+
await (0, node_fs_promises.writeFile)(node_path.default.join(ctx.config.outDir, "og-default.png"), png);
|
|
4434
|
+
}
|
|
4360
4435
|
await persistDiskCache(ctx.config.outDir, cache);
|
|
4361
4436
|
ctx.log.debug("build:og-images", {
|
|
4362
4437
|
rendered: tally.rendered,
|
|
4363
|
-
skipped: tally.skipped
|
|
4438
|
+
skipped: tally.skipped,
|
|
4439
|
+
defaultCard
|
|
4364
4440
|
});
|
|
4365
4441
|
return {
|
|
4366
4442
|
rendered: tally.rendered,
|
|
4367
4443
|
skipped: tally.skipped,
|
|
4368
|
-
peakConcurrency: tally.peakConcurrency
|
|
4444
|
+
peakConcurrency: tally.peakConcurrency,
|
|
4445
|
+
defaultCard
|
|
4369
4446
|
};
|
|
4370
4447
|
}
|
|
4371
4448
|
/**
|
package/dist/index.d.cts
CHANGED
|
@@ -1632,6 +1632,13 @@ interface OgImageConfig {
|
|
|
1632
1632
|
render?(input: RichOgInput): import("preact").VNode;
|
|
1633
1633
|
/** Explicit named fonts loaded once per build (overrides the first-file scan). */
|
|
1634
1634
|
fonts?: OgFont[];
|
|
1635
|
+
/**
|
|
1636
|
+
* When `true`, also render a single SITE-LEVEL default card to `<outDir>/og-default.png`
|
|
1637
|
+
* — a generic site name + description on a dark background, using the same loaded fonts (the
|
|
1638
|
+
* per-article `render` hook is NOT applied). Point `head.defaultOgImage` at `"/og-default.png"`
|
|
1639
|
+
* to use it as the og:image fallback for non-article pages. Default `false`.
|
|
1640
|
+
*/
|
|
1641
|
+
defaultCard?: boolean;
|
|
1635
1642
|
}
|
|
1636
1643
|
/**
|
|
1637
1644
|
* Public configuration for the `build` plugin. Flags give opt-in granularity over
|
package/dist/index.d.mts
CHANGED
|
@@ -1632,6 +1632,13 @@ interface OgImageConfig {
|
|
|
1632
1632
|
render?(input: RichOgInput): import("preact").VNode;
|
|
1633
1633
|
/** Explicit named fonts loaded once per build (overrides the first-file scan). */
|
|
1634
1634
|
fonts?: OgFont[];
|
|
1635
|
+
/**
|
|
1636
|
+
* When `true`, also render a single SITE-LEVEL default card to `<outDir>/og-default.png`
|
|
1637
|
+
* — a generic site name + description on a dark background, using the same loaded fonts (the
|
|
1638
|
+
* per-article `render` hook is NOT applied). Point `head.defaultOgImage` at `"/og-default.png"`
|
|
1639
|
+
* to use it as the og:image fallback for non-article pages. Default `false`.
|
|
1640
|
+
*/
|
|
1641
|
+
defaultCard?: boolean;
|
|
1635
1642
|
}
|
|
1636
1643
|
/**
|
|
1637
1644
|
* Public configuration for the `build` plugin. Flags give opt-in granularity over
|
package/dist/index.mjs
CHANGED
|
@@ -4161,6 +4161,45 @@ function defaultCard(input) {
|
|
|
4161
4161
|
} }, input.title);
|
|
4162
4162
|
}
|
|
4163
4163
|
/**
|
|
4164
|
+
* The built-in SITE-LEVEL default card — the site name over its description on a dark
|
|
4165
|
+
* background, centered. Rendered once (when `ogImage.defaultCard` is true) to `og-default.png`
|
|
4166
|
+
* and used as the `head.defaultOgImage` fallback. Reads `siteName` + `description` from the
|
|
4167
|
+
* {@link RichOgInput}; the per-article `render` hook is deliberately NOT applied here.
|
|
4168
|
+
*
|
|
4169
|
+
* @param input - The rich OG input (only `siteName` + `description` are used).
|
|
4170
|
+
* @returns The Preact `VNode` for the site default card.
|
|
4171
|
+
* @example
|
|
4172
|
+
* ```ts
|
|
4173
|
+
* defaultSiteCard({ ...input, siteName: "My Blog", description: "A dev blog" });
|
|
4174
|
+
* ```
|
|
4175
|
+
*/
|
|
4176
|
+
function defaultSiteCard(input) {
|
|
4177
|
+
const children = [h("div", { style: {
|
|
4178
|
+
display: "flex",
|
|
4179
|
+
fontSize: 72,
|
|
4180
|
+
fontWeight: 700,
|
|
4181
|
+
color: "#ffffff"
|
|
4182
|
+
} }, input.siteName)];
|
|
4183
|
+
if (input.description) children.push(h("div", { style: {
|
|
4184
|
+
display: "flex",
|
|
4185
|
+
marginTop: 28,
|
|
4186
|
+
maxWidth: 900,
|
|
4187
|
+
fontSize: 32,
|
|
4188
|
+
color: "#a1a1aa",
|
|
4189
|
+
textAlign: "center"
|
|
4190
|
+
} }, input.description));
|
|
4191
|
+
return h("div", { style: {
|
|
4192
|
+
display: "flex",
|
|
4193
|
+
flexDirection: "column",
|
|
4194
|
+
width: "100%",
|
|
4195
|
+
height: "100%",
|
|
4196
|
+
alignItems: "center",
|
|
4197
|
+
justifyContent: "center",
|
|
4198
|
+
padding: 80,
|
|
4199
|
+
background: "#0b0b0c"
|
|
4200
|
+
} }, ...children);
|
|
4201
|
+
}
|
|
4202
|
+
/**
|
|
4164
4203
|
* The default PNG renderer: a Preact `VNode` (custom `render` hook or the built-in
|
|
4165
4204
|
* card) is rendered to SVG by Satori, then rasterized to PNG by resvg. Both native
|
|
4166
4205
|
* deps are imported LAZILY (browser-safe goal); the VNode→Satori-input cast happens
|
|
@@ -4250,6 +4289,24 @@ function resolveSiteName(ctx) {
|
|
|
4250
4289
|
}
|
|
4251
4290
|
}
|
|
4252
4291
|
/**
|
|
4292
|
+
* Resolve the site description via `ctx.require(sitePlugin)`, falling back to `""` when the
|
|
4293
|
+
* site API is unavailable (e.g. unit mocks that omit it). Used by the site default card.
|
|
4294
|
+
*
|
|
4295
|
+
* @param ctx - Plugin context (provides `require`).
|
|
4296
|
+
* @returns The site description, or `""` when the site plugin is not wired.
|
|
4297
|
+
* @example
|
|
4298
|
+
* ```ts
|
|
4299
|
+
* resolveSiteDescription(ctx);
|
|
4300
|
+
* ```
|
|
4301
|
+
*/
|
|
4302
|
+
function resolveSiteDescription(ctx) {
|
|
4303
|
+
try {
|
|
4304
|
+
return ctx.require(sitePlugin).description();
|
|
4305
|
+
} catch {
|
|
4306
|
+
return "";
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
/**
|
|
4253
4310
|
* Render (or cache-skip) one article's OG image, mutating {@link RenderTally} in
|
|
4254
4311
|
* place. A matching cached hash bumps `skipped` and returns early; otherwise the
|
|
4255
4312
|
* PNG is rasterized to `<outDir>/og/<slug>.png`, the cache entry is updated, and
|
|
@@ -4320,6 +4377,10 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4320
4377
|
fonts,
|
|
4321
4378
|
...renderHook
|
|
4322
4379
|
});
|
|
4380
|
+
const renderSitePng = options.renderPng ?? makeDefaultRenderer({
|
|
4381
|
+
fonts,
|
|
4382
|
+
render: defaultSiteCard
|
|
4383
|
+
});
|
|
4323
4384
|
const siteName = resolveSiteName(ctx);
|
|
4324
4385
|
const defaultLocale = ctx.require(i18nPlugin).defaultLocale();
|
|
4325
4386
|
const articles = selectArticles(readCachedContent(ctx), defaultLocale);
|
|
@@ -4344,15 +4405,31 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
4344
4405
|
outDir
|
|
4345
4406
|
}, tally);
|
|
4346
4407
|
})));
|
|
4408
|
+
const defaultCard = config.defaultCard === true;
|
|
4409
|
+
if (defaultCard) {
|
|
4410
|
+
const png = await renderSitePng({
|
|
4411
|
+
title: siteName,
|
|
4412
|
+
description: resolveSiteDescription(ctx),
|
|
4413
|
+
date: "",
|
|
4414
|
+
tags: [],
|
|
4415
|
+
locale: defaultLocale,
|
|
4416
|
+
siteName,
|
|
4417
|
+
size
|
|
4418
|
+
});
|
|
4419
|
+
await mkdir(ctx.config.outDir, { recursive: true });
|
|
4420
|
+
await writeFile(path.join(ctx.config.outDir, "og-default.png"), png);
|
|
4421
|
+
}
|
|
4347
4422
|
await persistDiskCache(ctx.config.outDir, cache);
|
|
4348
4423
|
ctx.log.debug("build:og-images", {
|
|
4349
4424
|
rendered: tally.rendered,
|
|
4350
|
-
skipped: tally.skipped
|
|
4425
|
+
skipped: tally.skipped,
|
|
4426
|
+
defaultCard
|
|
4351
4427
|
});
|
|
4352
4428
|
return {
|
|
4353
4429
|
rendered: tally.rendered,
|
|
4354
4430
|
skipped: tally.skipped,
|
|
4355
|
-
peakConcurrency: tally.peakConcurrency
|
|
4431
|
+
peakConcurrency: tally.peakConcurrency,
|
|
4432
|
+
defaultCard
|
|
4356
4433
|
};
|
|
4357
4434
|
}
|
|
4358
4435
|
/**
|
package/package.json
CHANGED