@kensio/colophon 0.2.0 → 2.1.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 (46) hide show
  1. package/README.md +133 -12
  2. package/dist/config.d.ts +50 -3
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +62 -8
  5. package/dist/config.js.map +1 -1
  6. package/dist/content/index.d.ts +13 -0
  7. package/dist/content/index.d.ts.map +1 -1
  8. package/dist/content/index.js +23 -6
  9. package/dist/content/index.js.map +1 -1
  10. package/dist/generate.d.ts +8 -8
  11. package/dist/generate.d.ts.map +1 -1
  12. package/dist/generate.js +11 -20
  13. package/dist/generate.js.map +1 -1
  14. package/dist/highlight.d.ts +65 -0
  15. package/dist/highlight.d.ts.map +1 -0
  16. package/dist/highlight.js +114 -0
  17. package/dist/highlight.js.map +1 -0
  18. package/dist/index.d.ts +6 -4
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/render.d.ts +5 -2
  23. package/dist/render.d.ts.map +1 -1
  24. package/dist/render.js +10 -6
  25. package/dist/render.js.map +1 -1
  26. package/dist/templates/banner.d.ts.map +1 -1
  27. package/dist/templates/banner.js +2 -12
  28. package/dist/templates/banner.js.map +1 -1
  29. package/dist/templates/card.d.ts.map +1 -1
  30. package/dist/templates/card.js +2 -12
  31. package/dist/templates/card.js.map +1 -1
  32. package/dist/templates/code.d.ts +12 -0
  33. package/dist/templates/code.d.ts.map +1 -0
  34. package/dist/templates/code.js +203 -0
  35. package/dist/templates/code.js.map +1 -0
  36. package/dist/templates/index.d.ts +2 -0
  37. package/dist/templates/index.d.ts.map +1 -1
  38. package/dist/templates/index.js +4 -0
  39. package/dist/templates/index.js.map +1 -1
  40. package/dist/templates/props.d.ts +7 -0
  41. package/dist/templates/props.d.ts.map +1 -0
  42. package/dist/templates/props.js +17 -0
  43. package/dist/templates/props.js.map +1 -0
  44. package/dist/types.d.ts +57 -5
  45. package/dist/types.d.ts.map +1 -1
  46. package/package.json +9 -5
package/README.md CHANGED
@@ -10,6 +10,8 @@ finished work.
10
10
 
11
11
  - **Frontmatter-driven** — general props read from a post, not a fixed schema.
12
12
  - **Templates** — a small registry of layouts; frontmatter picks one.
13
+ - **Syntax-highlighted code images** — the `code` template renders a snippet
14
+ from frontmatter with real VS Code theme colours.
13
15
  - **Configurable branding** — colours, gradient, fonts, footer and badge come
14
16
  from config, not from any one site's stylesheet.
15
17
  - **Multiple sizes from one input** — a 1:1 square plus a 1.91:1 landscape by
@@ -23,7 +25,8 @@ finished work.
23
25
  pnpm add @kensio/colophon
24
26
  ```
25
27
 
26
- `sharp` is a dependency and does the SVG → PNG rasterisation.
28
+ `sharp` is a dependency and does the SVG → PNG rasterisation; `shiki` provides
29
+ the grammars and themes for the `code` template.
27
30
 
28
31
  ## Quick start (CLI)
29
32
 
@@ -59,9 +62,10 @@ Run it over a content tree:
59
62
  colophon content --config colophon.config.ts
60
63
  ```
61
64
 
62
- For every file that declares `meta_img_props`, Colophon writes a PNG next to it
63
- (`post/index.md` `post/post.png`, plus `post/post-1200x630.png` for the extra
64
- size). Existing files are skipped unless you pass `--overwrite`.
65
+ For every file that declares `meta_img_props`, Colophon writes one PNG per
66
+ output size next to it, named `<slug>-<size>.png`
67
+ (`post/index.md` `post/post-og.png` and `post/post-square.png`). Existing
68
+ files are skipped unless you pass `--overwrite`.
65
69
 
66
70
  ```
67
71
  colophon [contentDir] [options]
@@ -99,8 +103,8 @@ const images = await renderMetaImages(
99
103
  );
100
104
 
101
105
  for (const image of images) {
102
- const { width, height } = image.dimensions;
103
- await writeFile(`card-${width}x${height}.png`, image.png);
106
+ // image.name is the output-size name ("og", "square", …).
107
+ await writeFile(`social-${image.name}.png`, image.png);
104
108
  }
105
109
  ```
106
110
 
@@ -130,10 +134,74 @@ only want frontmatter discovery.
130
134
  | -------- | ---------------------------------------------------------------------------- |
131
135
  | `banner` | Left-aligned title with optional version, subtitle, corner badge and footer. |
132
136
  | `card` | Minimal centred title with an optional subtitle. |
137
+ | `code` | Syntax-highlighted snippet on a rounded panel over the background. |
133
138
 
134
139
  Register your own by passing `templates` in config — a template is `{ name,
135
- render(context) }` returning SVG foreground content. Anything you add merges
136
- over (and can override) the built-ins.
140
+ render(context) }` returning SVG foreground content, either directly or as a
141
+ promise. Anything you add merges over (and can override) the built-ins.
142
+
143
+ ### The `code` template
144
+
145
+ Put the snippet in frontmatter and name its language:
146
+
147
+ ```yaml
148
+ ---
149
+ title: eslint changed TypeScript files only
150
+ slug: eslint-changed-ts-files-only
151
+ meta_img_props:
152
+ template: code
153
+ language: bash
154
+ code: |
155
+ mapfile -t CHANGED_TS < <(
156
+ git diff origin/main --name-only \
157
+ | grep '\.ts'
158
+ )
159
+ ---
160
+ ```
161
+
162
+ | Prop | Notes |
163
+ | ---------- | -------------------------------------------------------------------- |
164
+ | `code` | The snippet. Surrounding blank lines are trimmed; tabs are expanded. |
165
+ | `language` | Any [Shiki language]; unknown names fall back to plain text. |
166
+ | `title` | Optional heading above the panel. Omit for a bare code image. |
167
+ | `theme` | Optional per-post override of `config.code.theme`. |
168
+
169
+ [Shiki language]: https://shiki.style/languages
170
+
171
+ Pygments-style names carried over from an older pipeline (`text`, `console`,
172
+ `html+handlebars`, …) are mapped onto their Shiki equivalents, so existing
173
+ frontmatter usually needs no changes.
174
+
175
+ The font size is fitted to the snippet: Colophon measures the longest line and
176
+ the line count against a monospace grid and picks the largest size that fits on
177
+ both axes, within `minFontScale`/`maxFontScale`. Code too long to fit legibly is
178
+ truncated with an ellipsis rather than shrunk into unreadability. The panel then
179
+ shrinks vertically onto the result so short snippets aren't left floating.
180
+
181
+ Styling comes from `config.code`:
182
+
183
+ ```ts
184
+ export default defineConfig({
185
+ colors: { brand: "#2563eb" },
186
+ footer: "example.com",
187
+ code: {
188
+ theme: "night-owl", // any bundled Shiki theme
189
+ fontFamily: '"JetBrains Mono", monospace',
190
+ charWidthRatio: 0.6, // glyph advance ÷ font size, for your monospace face
191
+ lineHeight: 1.55,
192
+ tabSize: 2,
193
+ cornerScale: 0.025,
194
+ maxFontScale: 0.075,
195
+ minFontScale: 0.018,
196
+ },
197
+ });
198
+ ```
199
+
200
+ `charWidthRatio` is how the layout knows where each token sits, so it must match
201
+ the font actually used — `0.6` suits most monospace faces (Source Code Pro,
202
+ Menlo, DejaVu Sans Mono); Consolas wants about `0.55`. Fonts must be installed
203
+ where `sharp` can see them; the default stack ends in the generic `monospace`
204
+ family so it always resolves to something.
137
205
 
138
206
  ## Configuration
139
207
 
@@ -146,14 +214,45 @@ All fields are optional; sensible defaults apply.
146
214
  | `fontFamily` | `Arial, Helvetica, sans-serif` | Uses fonts available to `sharp`/librsvg. |
147
215
  | `footer` | none | Footer text; omit the field for none. |
148
216
  | `badge` | none | Corner badge for `banner`; omit the field for none. |
149
- | `dimensions` | `1200×1200` and `1200×630` | Any list of `{ width, height }`. |
150
- | `templates` | `banner`, `card` | Merged over the built-ins. |
217
+ | `code` | `github-dark`, monospace stack | Styling for the `code` template (see above). |
218
+ | `sizes` | `og` + `square` | Named output sizes (see below). |
219
+ | `templates` | `banner`, `card`, `code` | Merged over the built-ins. |
220
+
221
+ ### Output sizes and filenames
222
+
223
+ Each output size is a named `{ name, width, height }`. The `name` becomes the
224
+ filename suffix, so every image is distinct: `my-post-og.png`,
225
+ `my-post-square.png`. The default set is one 1.91:1 Open Graph landscape and one
226
+ 1:1 square, which between them satisfy `og:image` and both `twitter:image` card
227
+ types (`summary_large_image` reuses the landscape; `summary` uses the square).
228
+
229
+ `SIZE_PRESETS` ships the common standards — compose your own set:
230
+
231
+ ```ts
232
+ import { defineConfig, SIZE_PRESETS } from "@kensio/colophon";
233
+
234
+ export default defineConfig({
235
+ sizes: [
236
+ SIZE_PRESETS.og, // 1200×630 — og:image (Facebook, LinkedIn, Slack, …)
237
+ SIZE_PRESETS.square, // 1200×1200 — Twitter summary card, universal
238
+ SIZE_PRESETS.twitter, // 1200×600 (2:1) — Twitter summary_large_image
239
+ SIZE_PRESETS.pinterest, // 1000×1500 (2:3) — Pinterest
240
+ { name: "hero", width: 1600, height: 900 }, // or anything custom
241
+ ],
242
+ });
243
+ ```
244
+
245
+ The base filename is the **post slug**: Colophon reads a top-level `slug` from
246
+ frontmatter (SEO-friendly, keyword-rich), falling back to the file name — or the
247
+ parent directory for `index.*` files. Point `slugField` at a different key, or
248
+ override naming entirely with `generate`'s `outputPath` callback.
151
249
 
152
250
  ### Frontmatter shape
153
251
 
154
252
  By default Colophon reads a `meta_img_props` object and a `template` field
155
- within it. Both are configurable via walk options (`propsKey`, `templateField`,
156
- `defaultTemplate`, `extensions`) so you can match an existing convention.
253
+ within it, plus a top-level `slug`. All are configurable via walk options
254
+ (`propsKey`, `templateField`, `defaultTemplate`, `slugField`, `extensions`) so
255
+ you can match an existing convention.
157
256
 
158
257
  ## Sample output
159
258
 
@@ -182,8 +281,30 @@ updated PNGs so this gallery stays in sync.
182
281
  <sub><code>card</code> · 1200×630 · solid background, title only</sub>
183
282
  </td>
184
283
  </tr>
284
+ <tr>
285
+ <td>
286
+ <img src="docs/samples/code-square.png" alt="code template, square" width="100%" /><br />
287
+ <sub><code>code</code> · 1200×1200 · bash, <code>github-dark</code></sub>
288
+ </td>
289
+ <td>
290
+ <img src="docs/samples/code-wide.png" alt="code template, landscape" width="100%" /><br />
291
+ <sub><code>code</code> · 1200×630 · TypeScript, <code>night-owl</code></sub>
292
+ </td>
293
+ </tr>
185
294
  </table>
186
295
 
296
+ ## Upgrading from 1.x
297
+
298
+ Adding the `code` template made two small breaking changes:
299
+
300
+ - `Template.render` may now return `string | Promise<string>`, and `buildSvg`
301
+ is `async`. Custom templates that return a string still work unchanged; call
302
+ sites of `buildSvg` need an `await`. `renderMetaImages` and `generate` were
303
+ already async and are unaffected.
304
+ - `MetaImageProps.title` is optional, and `walkContent`/`extractProps` no
305
+ longer skip a file that declares props without a title — a `code` post
306
+ describes its image entirely through `code` and `language`.
307
+
187
308
  ## Development
188
309
 
189
310
  - `pnpm build` — compile to `dist/`.
package/dist/config.d.ts CHANGED
@@ -1,10 +1,57 @@
1
- import type { BrandColors, ColophonConfig, Dimensions, ResolvedConfig } from "./types.js";
2
- /** Default output sizes: a 1:1 square plus a 1.91:1 landscape (Open Graph). */
3
- export declare const DEFAULT_DIMENSIONS: readonly Dimensions[];
1
+ import type { BrandColors, CodeStyle, ColophonConfig, OutputSize, ResolvedConfig } from "./types.js";
2
+ /**
3
+ * Named output-size presets covering the common social-image standards. Each
4
+ * `name` becomes the filename suffix (e.g. `my-post-og.png`).
5
+ *
6
+ * - `og` — 1.91:1, the Open Graph standard (`og:image`): Facebook, LinkedIn,
7
+ * Slack, Discord, WhatsApp, Mastodon, and the usual `twitter:image` reuse.
8
+ * - `square` — 1:1, X/Twitter `summary` card and a universal fallback.
9
+ * - `twitter` — 2:1, X/Twitter `summary_large_image` card.
10
+ * - `pinterest` — 2:3 tall pin.
11
+ */
12
+ export declare const SIZE_PRESETS: {
13
+ readonly og: {
14
+ readonly name: "og";
15
+ readonly width: 1200;
16
+ readonly height: 630;
17
+ };
18
+ readonly square: {
19
+ readonly name: "square";
20
+ readonly width: 1200;
21
+ readonly height: 1200;
22
+ };
23
+ readonly twitter: {
24
+ readonly name: "twitter";
25
+ readonly width: 1200;
26
+ readonly height: 600;
27
+ };
28
+ readonly pinterest: {
29
+ readonly name: "pinterest";
30
+ readonly width: 1000;
31
+ readonly height: 1500;
32
+ };
33
+ };
34
+ /**
35
+ * Default output sizes: the Open Graph landscape plus a square. Between them
36
+ * they satisfy `og:image` and both `twitter:image` card types.
37
+ */
38
+ export declare const DEFAULT_SIZES: readonly OutputSize[];
4
39
  /** Default font stack. Override via `config.fontFamily` for branded fonts. */
5
40
  export declare const DEFAULT_FONT_FAMILY = "Arial, Helvetica, sans-serif";
6
41
  /** Neutral default palette, used when no `colors.brand` is supplied. */
7
42
  export declare const DEFAULT_COLORS: Required<BrandColors>;
43
+ /**
44
+ * Default monospace stack for the `code` template. It ends in the generic
45
+ * `monospace` family so it always resolves to something, whatever fonts the
46
+ * machine running the build happens to have.
47
+ */
48
+ export declare const DEFAULT_CODE_FONT_FAMILY = "\"JetBrains Mono\", \"Source Code Pro\", \"DejaVu Sans Mono\", Menlo, Consolas, monospace";
49
+ /**
50
+ * Default `code` template styling. `charWidthRatio` and `lineHeight` drive the
51
+ * monospace grid the snippet is laid out on; the font-size bounds are
52
+ * fractions of the image height so they hold at every output size.
53
+ */
54
+ export declare const DEFAULT_CODE_STYLE: Required<CodeStyle>;
8
55
  /**
9
56
  * Identity helper that returns its argument typed as {@link ColophonConfig}.
10
57
  * Use it in a config module to get editor completion and type-checking.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,WAAW,EACX,cAAc,EACd,UAAU,EACV,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,EAAE,SAAS,UAAU,EAGnD,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE,wEAAwE;AACxE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,WAAW,CAKhD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAEnE;AA4BD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,cAAmB,GAAG,cAAc,CAgBzE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,WAAW,EACX,SAAS,EACT,cAAc,EACd,UAAU,EACV,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY;;iBACjB,IAAI,EAAE,IAAI;iBAAE,KAAK,EAAE,IAAI;iBAAE,MAAM,EAAE,GAAG;;;iBAChC,IAAI,EAAE,QAAQ;iBAAE,KAAK,EAAE,IAAI;iBAAE,MAAM,EAAE,IAAI;;;iBACxC,IAAI,EAAE,SAAS;iBAAE,KAAK,EAAE,IAAI;iBAAE,MAAM,EAAE,GAAG;;;iBACvC,IAAI,EAAE,WAAW;iBAAE,KAAK,EAAE,IAAI;iBAAE,MAAM,EAAE,IAAI;;CACZ,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,UAAU,EAG9C,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE,wEAAwE;AACxE,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,WAAW,CAKhD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,8FACkD,CAAC;AAExF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,SAAS,CASlD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAEnE;AAoDD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,cAAmB,GAAG,cAAc,CAazE"}
package/dist/config.js CHANGED
@@ -1,8 +1,27 @@
1
1
  import { builtinTemplates } from "./templates/index.js";
2
- /** Default output sizes: a 1:1 square plus a 1.91:1 landscape (Open Graph). */
3
- export const DEFAULT_DIMENSIONS = [
4
- { width: 1200, height: 1200 },
5
- { width: 1200, height: 630 },
2
+ /**
3
+ * Named output-size presets covering the common social-image standards. Each
4
+ * `name` becomes the filename suffix (e.g. `my-post-og.png`).
5
+ *
6
+ * - `og` — 1.91:1, the Open Graph standard (`og:image`): Facebook, LinkedIn,
7
+ * Slack, Discord, WhatsApp, Mastodon, and the usual `twitter:image` reuse.
8
+ * - `square` — 1:1, X/Twitter `summary` card and a universal fallback.
9
+ * - `twitter` — 2:1, X/Twitter `summary_large_image` card.
10
+ * - `pinterest` — 2:3 tall pin.
11
+ */
12
+ export const SIZE_PRESETS = {
13
+ og: { name: "og", width: 1200, height: 630 },
14
+ square: { name: "square", width: 1200, height: 1200 },
15
+ twitter: { name: "twitter", width: 1200, height: 600 },
16
+ pinterest: { name: "pinterest", width: 1000, height: 1500 },
17
+ };
18
+ /**
19
+ * Default output sizes: the Open Graph landscape plus a square. Between them
20
+ * they satisfy `og:image` and both `twitter:image` card types.
21
+ */
22
+ export const DEFAULT_SIZES = [
23
+ SIZE_PRESETS.og,
24
+ SIZE_PRESETS.square,
6
25
  ];
7
26
  /** Default font stack. Override via `config.fontFamily` for branded fonts. */
8
27
  export const DEFAULT_FONT_FAMILY = "Arial, Helvetica, sans-serif";
@@ -13,6 +32,27 @@ export const DEFAULT_COLORS = {
13
32
  brandWarm: "#db2777",
14
33
  foreground: "#ffffff",
15
34
  };
35
+ /**
36
+ * Default monospace stack for the `code` template. It ends in the generic
37
+ * `monospace` family so it always resolves to something, whatever fonts the
38
+ * machine running the build happens to have.
39
+ */
40
+ export const DEFAULT_CODE_FONT_FAMILY = '"JetBrains Mono", "Source Code Pro", "DejaVu Sans Mono", Menlo, Consolas, monospace';
41
+ /**
42
+ * Default `code` template styling. `charWidthRatio` and `lineHeight` drive the
43
+ * monospace grid the snippet is laid out on; the font-size bounds are
44
+ * fractions of the image height so they hold at every output size.
45
+ */
46
+ export const DEFAULT_CODE_STYLE = {
47
+ theme: "github-dark",
48
+ fontFamily: DEFAULT_CODE_FONT_FAMILY,
49
+ charWidthRatio: 0.6,
50
+ lineHeight: 1.55,
51
+ tabSize: 2,
52
+ cornerScale: 0.025,
53
+ maxFontScale: 0.075,
54
+ minFontScale: 0.018,
55
+ };
16
56
  /**
17
57
  * Identity helper that returns its argument typed as {@link ColophonConfig}.
18
58
  * Use it in a config module to get editor completion and type-checking.
@@ -43,21 +83,35 @@ function defaultBackground(colors) {
43
83
  ],
44
84
  };
45
85
  }
86
+ function resolveCode(code) {
87
+ return { ...DEFAULT_CODE_STYLE, ...code };
88
+ }
89
+ function resolveSizes(sizes) {
90
+ if (sizes === undefined || sizes.length === 0) {
91
+ return DEFAULT_SIZES;
92
+ }
93
+ const seen = new Set();
94
+ for (const size of sizes) {
95
+ if (seen.has(size.name)) {
96
+ throw new Error(`Duplicate output size name "${size.name}"; names must be unique so each image gets a distinct filename.`);
97
+ }
98
+ seen.add(size.name);
99
+ }
100
+ return sizes;
101
+ }
46
102
  /**
47
103
  * Apply defaults to a user config. Safe to call with no argument.
48
104
  */
49
105
  export function resolveConfig(config = {}) {
50
106
  const colors = resolveColors(config.colors);
51
- const dimensions = config.dimensions && config.dimensions.length > 0
52
- ? config.dimensions
53
- : DEFAULT_DIMENSIONS;
54
107
  return {
55
108
  colors,
56
109
  background: config.background ?? defaultBackground(colors),
57
110
  fontFamily: config.fontFamily ?? DEFAULT_FONT_FAMILY,
58
111
  footer: config.footer,
59
112
  badge: config.badge,
60
- dimensions,
113
+ code: resolveCode(config.code),
114
+ sizes: resolveSizes(config.sizes),
61
115
  templates: { ...builtinTemplates, ...config.templates },
62
116
  };
63
117
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AASxD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,kBAAkB,GAA0B;IACvD,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAC7B,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;CAC7B,CAAC;AAEF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAElE,wEAAwE;AACxE,MAAM,CAAC,MAAM,cAAc,GAA0B;IACnD,KAAK,EAAE,SAAS;IAChB,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,SAAS;IACpB,UAAU,EAAE,SAAS;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,MAA+B;IACpD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,6EAA6E;IAC7E,0DAA0D;IAC1D,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK;QAC3C,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK;QAC3C,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,cAAc,CAAC,UAAU;KAC3D,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,MAA6B;IACtD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE;YACL,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE;YACzC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;YACtC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE;SAC5C;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAM,GAAmB,EAAE;IACvD,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,UAAU,GACd,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;QAC/C,CAAC,CAAC,MAAM,CAAC,UAAU;QACnB,CAAC,CAAC,kBAAkB,CAAC;IAEzB,OAAO;QACL,MAAM;QACN,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,iBAAiB,CAAC,MAAM,CAAC;QAC1D,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,mBAAmB;QACpD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,UAAU;QACV,SAAS,EAAE,EAAE,GAAG,gBAAgB,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE;KACxD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,11 @@ export interface WalkOptions {
11
11
  readonly templateField?: string;
12
12
  /** Template to use when the template field is absent. */
13
13
  readonly defaultTemplate?: string;
14
+ /**
15
+ * Top-level frontmatter field to read the post slug from (used as the base
16
+ * filename). Default `slug`; falls back to the file/directory name.
17
+ */
18
+ readonly slugField?: string;
14
19
  /** File extensions to include. Default `.md` and `.markdown`. */
15
20
  readonly extensions?: readonly string[];
16
21
  }
@@ -22,8 +27,16 @@ export interface ContentFile {
22
27
  readonly contentPath: string;
23
28
  /** Absolute path on disk. */
24
29
  readonly absolutePath: string;
30
+ /** Base filename for this post's images (frontmatter slug, or path-derived). */
31
+ readonly slug: string;
25
32
  readonly props: MetaImageProps;
26
33
  }
34
+ /**
35
+ * Derive a slug from a file path: the filename without extension, or the
36
+ * parent directory name when the file is `index.*` (the common page-bundle
37
+ * convention).
38
+ */
39
+ export declare function slugFromPath(filePath: string): string;
27
40
  /**
28
41
  * Extract {@link MetaImageProps} from a parsed frontmatter object, or return
29
42
  * `undefined` if this file should be skipped (no props object, or no usable
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAsBlD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,yDAAyD;IACzD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,GAAE,IAAI,CACX,WAAW,EACX,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAC5C,GACL,cAAc,GAAG,SAAS,CA+C5B;AA8BD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,EAAE,CAAC,CAsBxB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAuBlD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,yDAAyD;IACzD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIrD;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,GAAE,IAAI,CACX,WAAW,EACX,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAC5C,GACL,cAAc,GAAG,SAAS,CA4C5B;AA8BD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,EAAE,CAAC,CAgCxB"}
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import matter from "gray-matter";
4
4
  const defaultPropsKey = "meta_img_props";
5
5
  const defaultTemplateField = "template";
6
+ const defaultSlugField = "slug";
6
7
  const defaultExtensions = [".md", ".markdown"];
7
8
  function coerceString(value) {
8
9
  if (typeof value === "string") {
@@ -15,6 +16,16 @@ function coerceString(value) {
15
16
  }
16
17
  return undefined;
17
18
  }
19
+ /**
20
+ * Derive a slug from a file path: the filename without extension, or the
21
+ * parent directory name when the file is `index.*` (the common page-bundle
22
+ * convention).
23
+ */
24
+ export function slugFromPath(filePath) {
25
+ const extension = path.extname(filePath);
26
+ const base = path.basename(filePath, extension);
27
+ return base === "index" ? path.basename(path.dirname(filePath)) : base;
28
+ }
18
29
  function isRecord(value) {
19
30
  return typeof value === "object" && value !== null && !Array.isArray(value);
20
31
  }
@@ -35,10 +46,9 @@ export function extractProps(frontmatter, options = {}) {
35
46
  if (template === undefined) {
36
47
  return undefined;
37
48
  }
38
- const titleRaw = record["title"];
39
- if (typeof titleRaw !== "string") {
40
- return undefined;
41
- }
49
+ // Title is optional: templates such as `code` describe the image entirely
50
+ // from their own fields, and requiring a title would be pure boilerplate.
51
+ const title = coerceString(record["title"]);
42
52
  const subtitle = coerceString(record["subtitle"]);
43
53
  const version = coerceString(record["version"]);
44
54
  const extras = {};
@@ -54,7 +64,7 @@ export function extractProps(frontmatter, options = {}) {
54
64
  return {
55
65
  ...extras,
56
66
  template,
57
- title: titleRaw,
67
+ ...(title !== undefined && { title }),
58
68
  ...(subtitle !== undefined && { subtitle }),
59
69
  ...(version !== undefined && { version }),
60
70
  };
@@ -82,15 +92,22 @@ async function collectContentFiles(dir, extensions) {
82
92
  export async function walkContent(options) {
83
93
  const extensions = options.extensions ?? defaultExtensions;
84
94
  const filePaths = await collectContentFiles(options.dir, extensions);
95
+ const slugField = options.slugField ?? defaultSlugField;
85
96
  const files = await Promise.all(filePaths.map(async (filePath) => {
86
97
  const raw = await readFile(filePath, "utf8");
87
- const props = extractProps(matter(raw).data, options);
98
+ const frontmatter = matter(raw).data;
99
+ const props = extractProps(frontmatter, options);
88
100
  if (props === undefined) {
89
101
  return;
90
102
  }
103
+ const declaredSlug = coerceString(frontmatter[slugField])?.trim();
104
+ const slug = declaredSlug !== undefined && declaredSlug !== ""
105
+ ? declaredSlug
106
+ : slugFromPath(filePath);
91
107
  return {
92
108
  contentPath: path.relative(options.dir, filePath),
93
109
  absolutePath: filePath,
110
+ slug,
94
111
  props,
95
112
  };
96
113
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import type { ContentFile, WalkOptions } from "./content/index.js";
2
- import type { ColophonConfig, Dimensions } from "./types.js";
2
+ import type { ColophonConfig, OutputSize } from "./types.js";
3
3
  /**
4
4
  * Outcome for one generated (or skipped) image.
5
5
  */
6
6
  export interface GeneratedImage {
7
7
  readonly contentPath: string;
8
- readonly dimensions: Dimensions;
8
+ readonly size: OutputSize;
9
9
  readonly outputPath: string;
10
10
  /** True when an existing file was left in place (no `overwrite`). */
11
11
  readonly skipped: boolean;
@@ -17,21 +17,21 @@ export interface GenerateOptions {
17
17
  /** Root content directory to walk. */
18
18
  readonly contentDir: string;
19
19
  readonly config?: ColophonConfig;
20
- /** Extra walk options (props key, template field, extensions, ). */
20
+ /** Extra walk options (props key, template field, slug field, extensions). */
21
21
  readonly walk?: Omit<WalkOptions, "dir">;
22
22
  /** Override where each image is written. */
23
- readonly outputPath?: (file: ContentFile, dimensions: Dimensions, index: number) => string;
23
+ readonly outputPath?: (file: ContentFile, size: OutputSize) => string;
24
24
  /** Re-render even when the output file already exists. Default `false`. */
25
25
  readonly overwrite?: boolean;
26
26
  /** Called after each image is written or skipped. */
27
27
  readonly onResult?: (result: GeneratedImage) => void;
28
28
  }
29
29
  /**
30
- * Default output path: alongside the content file, named after the file (or
31
- * its parent directory when the file is `index.*`). The first (square) size
32
- * keeps the bare name; additional sizes get a `-WxH` suffix.
30
+ * Default output path: alongside the content file, named `<slug>-<size>.png`.
31
+ * The slug carries the post's keywords into the filename and the size name
32
+ * keeps every image distinct (e.g. `my-post-og.png`, `my-post-square.png`).
33
33
  */
34
- export declare function defaultOutputPath(file: ContentFile, dimensions: Dimensions, index: number): string;
34
+ export declare function defaultOutputPath(file: ContentFile, size: OutputSize): string;
35
35
  /**
36
36
  * Walk a content tree and render meta images for every file that declares
37
37
  * props, writing PNGs to disk. Existing files are skipped unless `overwrite`
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGnE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACzC,4CAA4C;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,CACpB,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,MAAM,KACV,MAAM,CAAC;IACZ,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,MAAM,GACZ,MAAM,CAWR;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,EAAE,CAAC,CAmC3B"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGnE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACzC,4CAA4C;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;IACtE,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAG7E;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,EAAE,CAAC,CAgC3B"}
package/dist/generate.js CHANGED
@@ -5,19 +5,13 @@ import { resolveConfig } from "./config.js";
5
5
  import { walkContent } from "./content/index.js";
6
6
  import { buildSvg, renderSvgToPng } from "./render.js";
7
7
  /**
8
- * Default output path: alongside the content file, named after the file (or
9
- * its parent directory when the file is `index.*`). The first (square) size
10
- * keeps the bare name; additional sizes get a `-WxH` suffix.
8
+ * Default output path: alongside the content file, named `<slug>-<size>.png`.
9
+ * The slug carries the post's keywords into the filename and the size name
10
+ * keeps every image distinct (e.g. `my-post-og.png`, `my-post-square.png`).
11
11
  */
12
- export function defaultOutputPath(file, dimensions, index) {
12
+ export function defaultOutputPath(file, size) {
13
13
  const directory = path.dirname(file.absolutePath);
14
- const extension = path.extname(file.contentPath);
15
- const base = path.basename(file.contentPath, extension);
16
- const stem = base === "index" ? path.basename(directory) : base;
17
- const suffix = index === 0
18
- ? ""
19
- : `-${String(dimensions.width)}x${String(dimensions.height)}`;
20
- return path.join(directory, `${stem}${suffix}.png`);
14
+ return path.join(directory, `${file.slug}-${size.name}.png`);
21
15
  }
22
16
  /**
23
17
  * Walk a content tree and render meta images for every file that declares
@@ -29,23 +23,20 @@ export async function generate(options) {
29
23
  const resolved = resolveConfig(options.config);
30
24
  const toOutputPath = options.outputPath ?? defaultOutputPath;
31
25
  const files = await walkContent({ dir: options.contentDir, ...options.walk });
32
- const jobs = files.flatMap((file) => resolved.dimensions.map((dimensions, index) => ({
33
- file,
34
- dimensions,
35
- index,
36
- })));
37
- return Promise.all(jobs.map(async ({ file, dimensions, index }) => {
38
- const outputPath = toOutputPath(file, dimensions, index);
26
+ const jobs = files.flatMap((file) => resolved.sizes.map((size) => ({ file, size })));
27
+ return Promise.all(jobs.map(async ({ file, size }) => {
28
+ const outputPath = toOutputPath(file, size);
39
29
  const isSkipped = existsSync(outputPath) && options.overwrite !== true;
40
30
  if (!isSkipped) {
41
- const svg = buildSvg(file.props, resolved, dimensions);
31
+ const dimensions = { width: size.width, height: size.height };
32
+ const svg = await buildSvg(file.props, resolved, dimensions);
42
33
  const png = await renderSvgToPng(svg, dimensions);
43
34
  await mkdir(path.dirname(outputPath), { recursive: true });
44
35
  await writeFile(outputPath, png);
45
36
  }
46
37
  const result = {
47
38
  contentPath: file.contentPath,
48
- dimensions,
39
+ size,
49
40
  outputPath,
50
41
  skipped: isSkipped,
51
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA+BvD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAiB,EAAE,IAAgB;IACnE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAwB;IAExB,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC;IAC7D,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAE9E,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAC/C,CAAC;IAEF,OAAO,OAAO,CAAC,GAAG,CAChB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;QAChC,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC;QAEvE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAClD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,MAAM,GAAmB;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,IAAI;YACJ,UAAU;YACV,OAAO,EAAE,SAAS;SACnB,CAAC;QACF,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}