@kensio/colophon 2.3.0 → 2.4.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 (301) hide show
  1. package/README.md +62 -801
  2. package/dist/background.d.ts +7 -2
  3. package/dist/background.d.ts.map +1 -1
  4. package/dist/background.js +44 -1
  5. package/dist/background.js.map +1 -1
  6. package/dist/cli/args.d.ts +1 -1
  7. package/dist/cli/args.d.ts.map +1 -1
  8. package/dist/cli/args.js +1 -1
  9. package/dist/cli/config.d.ts +1 -1
  10. package/dist/cli/config.js +1 -1
  11. package/dist/config/defaults.d.ts +8 -7
  12. package/dist/config/defaults.d.ts.map +1 -1
  13. package/dist/config/defaults.js +8 -8
  14. package/dist/config/defaults.js.map +1 -1
  15. package/dist/config/index.d.ts.map +1 -1
  16. package/dist/config/index.js +5 -3
  17. package/dist/config/index.js.map +1 -1
  18. package/dist/config/resolve.d.ts +7 -0
  19. package/dist/config/resolve.d.ts.map +1 -1
  20. package/dist/config/resolve.js +16 -0
  21. package/dist/config/resolve.js.map +1 -1
  22. package/dist/config/size.d.ts +1 -1
  23. package/dist/config/size.d.ts.map +1 -1
  24. package/dist/config/size.js +3 -2
  25. package/dist/config/size.js.map +1 -1
  26. package/dist/content/props.d.ts +2 -2
  27. package/dist/content/props.js +2 -2
  28. package/dist/content/slug.d.ts +5 -5
  29. package/dist/content/slug.js +6 -6
  30. package/dist/content/slug.js.map +1 -1
  31. package/dist/content/walk.d.ts +1 -1
  32. package/dist/content/walk.js +1 -1
  33. package/dist/fonts/index.d.ts +3 -2
  34. package/dist/fonts/index.d.ts.map +1 -1
  35. package/dist/fonts/index.js +3 -2
  36. package/dist/fonts/index.js.map +1 -1
  37. package/dist/fonts/resolve.js +1 -1
  38. package/dist/generate/extra.js +4 -4
  39. package/dist/generate/extra.js.map +1 -1
  40. package/dist/generate/options.d.ts +1 -1
  41. package/dist/generate/outputs.d.ts +4 -4
  42. package/dist/generate/outputs.js +4 -4
  43. package/dist/highlight/language.d.ts +2 -3
  44. package/dist/highlight/language.d.ts.map +1 -1
  45. package/dist/highlight/language.js +3 -4
  46. package/dist/highlight/language.js.map +1 -1
  47. package/dist/highlight/normalise.d.ts +2 -2
  48. package/dist/highlight/normalise.js +2 -2
  49. package/dist/image/index.d.ts +18 -0
  50. package/dist/image/index.d.ts.map +1 -0
  51. package/dist/image/index.js +42 -0
  52. package/dist/image/index.js.map +1 -0
  53. package/dist/image/jpeg.d.ts +10 -0
  54. package/dist/image/jpeg.d.ts.map +1 -0
  55. package/dist/image/jpeg.js +57 -0
  56. package/dist/image/jpeg.js.map +1 -0
  57. package/dist/image/load.d.ts +4 -0
  58. package/dist/image/load.d.ts.map +1 -0
  59. package/dist/image/load.js +60 -0
  60. package/dist/image/load.js.map +1 -0
  61. package/dist/image/media.d.ts +10 -0
  62. package/dist/image/media.d.ts.map +1 -0
  63. package/dist/image/media.js +37 -0
  64. package/dist/image/media.js.map +1 -0
  65. package/dist/image/resolve.d.ts +13 -0
  66. package/dist/image/resolve.d.ts.map +1 -0
  67. package/dist/image/resolve.js +38 -0
  68. package/dist/image/resolve.js.map +1 -0
  69. package/dist/image/size.d.ts +22 -0
  70. package/dist/image/size.d.ts.map +1 -0
  71. package/dist/image/size.js +60 -0
  72. package/dist/image/size.js.map +1 -0
  73. package/dist/image/svg.d.ts +12 -0
  74. package/dist/image/svg.d.ts.map +1 -0
  75. package/dist/image/svg.js +61 -0
  76. package/dist/image/svg.js.map +1 -0
  77. package/dist/image/uri.d.ts +9 -0
  78. package/dist/image/uri.d.ts.map +1 -0
  79. package/dist/image/uri.js +22 -0
  80. package/dist/image/uri.js.map +1 -0
  81. package/dist/index.d.ts +6 -2
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +5 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/layout/block.d.ts +37 -0
  86. package/dist/layout/block.d.ts.map +1 -0
  87. package/dist/layout/block.js +26 -0
  88. package/dist/layout/block.js.map +1 -0
  89. package/dist/layout/box.d.ts +20 -0
  90. package/dist/layout/box.d.ts.map +1 -0
  91. package/dist/layout/box.js +61 -0
  92. package/dist/layout/box.js.map +1 -0
  93. package/dist/layout/distribute.d.ts +15 -0
  94. package/dist/layout/distribute.d.ts.map +1 -0
  95. package/dist/layout/distribute.js +30 -0
  96. package/dist/layout/distribute.js.map +1 -0
  97. package/dist/layout/image.d.ts +42 -0
  98. package/dist/layout/image.d.ts.map +1 -0
  99. package/dist/layout/image.js +34 -0
  100. package/dist/layout/image.js.map +1 -0
  101. package/dist/layout/index.d.ts +40 -0
  102. package/dist/layout/index.d.ts.map +1 -0
  103. package/dist/layout/index.js +30 -0
  104. package/dist/layout/index.js.map +1 -0
  105. package/dist/layout/lines.d.ts +45 -0
  106. package/dist/layout/lines.d.ts.map +1 -0
  107. package/dist/layout/lines.js +71 -0
  108. package/dist/layout/lines.js.map +1 -0
  109. package/dist/layout/measure.d.ts +11 -0
  110. package/dist/layout/measure.d.ts.map +1 -0
  111. package/dist/layout/measure.js +11 -0
  112. package/dist/layout/measure.js.map +1 -0
  113. package/dist/layout/panel.d.ts +20 -0
  114. package/dist/layout/panel.d.ts.map +1 -0
  115. package/dist/layout/panel.js +22 -0
  116. package/dist/layout/panel.js.map +1 -0
  117. package/dist/layout/row.d.ts +15 -0
  118. package/dist/layout/row.d.ts.map +1 -0
  119. package/dist/layout/row.js +20 -0
  120. package/dist/layout/row.js.map +1 -0
  121. package/dist/layout/scrim.d.ts +23 -0
  122. package/dist/layout/scrim.d.ts.map +1 -0
  123. package/dist/layout/scrim.js +38 -0
  124. package/dist/layout/scrim.js.map +1 -0
  125. package/dist/layout/stack.d.ts +14 -0
  126. package/dist/layout/stack.d.ts.map +1 -0
  127. package/dist/layout/stack.js +19 -0
  128. package/dist/layout/stack.js.map +1 -0
  129. package/dist/layout/types.d.ts +49 -0
  130. package/dist/layout/types.d.ts.map +1 -0
  131. package/dist/layout/types.js +2 -0
  132. package/dist/layout/types.js.map +1 -0
  133. package/dist/manifest/build.d.ts +1 -1
  134. package/dist/manifest/build.js +1 -1
  135. package/dist/manifest/index.d.ts +1 -1
  136. package/dist/manifest/index.js +1 -1
  137. package/dist/manifest/order.d.ts +1 -1
  138. package/dist/manifest/order.js +1 -1
  139. package/dist/manifest/page.d.ts +2 -2
  140. package/dist/manifest/page.js +3 -3
  141. package/dist/measure/estimate.d.ts +10 -0
  142. package/dist/measure/estimate.d.ts.map +1 -0
  143. package/dist/measure/estimate.js +58 -0
  144. package/dist/measure/estimate.js.map +1 -0
  145. package/dist/measure/faces.d.ts +15 -0
  146. package/dist/measure/faces.d.ts.map +1 -0
  147. package/dist/measure/faces.js +70 -0
  148. package/dist/measure/faces.js.map +1 -0
  149. package/dist/measure/index.d.ts +16 -0
  150. package/dist/measure/index.d.ts.map +1 -0
  151. package/dist/measure/index.js +0 -0
  152. package/dist/measure/index.js.map +1 -0
  153. package/dist/measure/runs.d.ts +17 -0
  154. package/dist/measure/runs.d.ts.map +1 -0
  155. package/dist/measure/runs.js +39 -0
  156. package/dist/measure/runs.js.map +1 -0
  157. package/dist/measure/select.d.ts +13 -0
  158. package/dist/measure/select.d.ts.map +1 -0
  159. package/dist/measure/select.js +47 -0
  160. package/dist/measure/select.js.map +1 -0
  161. package/dist/meta/tags.d.ts +6 -6
  162. package/dist/meta/tags.js +6 -6
  163. package/dist/meta/url.d.ts +4 -4
  164. package/dist/meta/url.js +4 -4
  165. package/dist/placement/check.d.ts +1 -1
  166. package/dist/placement/check.js +1 -1
  167. package/dist/placement/index.js +1 -1
  168. package/dist/placement/relative.d.ts +3 -3
  169. package/dist/placement/relative.js +3 -3
  170. package/dist/pool.d.ts +2 -2
  171. package/dist/pool.js +3 -3
  172. package/dist/pool.js.map +1 -1
  173. package/dist/props.d.ts +7 -0
  174. package/dist/props.d.ts.map +1 -0
  175. package/dist/props.js +17 -0
  176. package/dist/props.js.map +1 -0
  177. package/dist/render/svg.d.ts +4 -2
  178. package/dist/render/svg.d.ts.map +1 -1
  179. package/dist/render/svg.js +19 -4
  180. package/dist/render/svg.js.map +1 -1
  181. package/dist/stamp/config-digest.d.ts.map +1 -1
  182. package/dist/stamp/config-digest.js +20 -1
  183. package/dist/stamp/config-digest.js.map +1 -1
  184. package/dist/stamp/index.js +2 -2
  185. package/dist/stamp/index.js.map +1 -1
  186. package/dist/stamp/read.d.ts +1 -1
  187. package/dist/stamp/read.js +4 -4
  188. package/dist/templates/attribution.d.ts +17 -0
  189. package/dist/templates/attribution.d.ts.map +1 -0
  190. package/dist/templates/attribution.js +39 -0
  191. package/dist/templates/attribution.js.map +1 -0
  192. package/dist/templates/banner/badge.d.ts.map +1 -1
  193. package/dist/templates/banner/badge.js +3 -6
  194. package/dist/templates/banner/badge.js.map +1 -1
  195. package/dist/templates/banner/index.d.ts +3 -0
  196. package/dist/templates/banner/index.d.ts.map +1 -1
  197. package/dist/templates/banner/index.js +37 -35
  198. package/dist/templates/banner/index.js.map +1 -1
  199. package/dist/templates/banner/lines.d.ts +7 -12
  200. package/dist/templates/banner/lines.d.ts.map +1 -1
  201. package/dist/templates/banner/lines.js +23 -34
  202. package/dist/templates/banner/lines.js.map +1 -1
  203. package/dist/templates/banner/version.d.ts +9 -0
  204. package/dist/templates/banner/version.d.ts.map +1 -0
  205. package/dist/templates/banner/version.js +21 -0
  206. package/dist/templates/banner/version.js.map +1 -0
  207. package/dist/templates/card/index.d.ts +4 -1
  208. package/dist/templates/card/index.d.ts.map +1 -1
  209. package/dist/templates/card/index.js +37 -25
  210. package/dist/templates/card/index.js.map +1 -1
  211. package/dist/templates/card/lines.d.ts +17 -13
  212. package/dist/templates/card/lines.d.ts.map +1 -1
  213. package/dist/templates/card/lines.js +24 -20
  214. package/dist/templates/card/lines.js.map +1 -1
  215. package/dist/templates/code/chrome.d.ts +7 -3
  216. package/dist/templates/code/chrome.d.ts.map +1 -1
  217. package/dist/templates/code/chrome.js +12 -11
  218. package/dist/templates/code/chrome.js.map +1 -1
  219. package/dist/templates/code/clip.d.ts +1 -1
  220. package/dist/templates/code/clip.js +1 -1
  221. package/dist/templates/code/fit.d.ts +2 -2
  222. package/dist/templates/code/fit.d.ts.map +1 -1
  223. package/dist/templates/code/fit.js +4 -4
  224. package/dist/templates/code/fit.js.map +1 -1
  225. package/dist/templates/code/index.d.ts.map +1 -1
  226. package/dist/templates/code/index.js +7 -6
  227. package/dist/templates/code/index.js.map +1 -1
  228. package/dist/templates/code/layout.d.ts +1 -1
  229. package/dist/templates/code/layout.d.ts.map +1 -1
  230. package/dist/templates/code/layout.js +6 -6
  231. package/dist/templates/code/layout.js.map +1 -1
  232. package/dist/templates/code/panel.d.ts +13 -0
  233. package/dist/templates/code/panel.d.ts.map +1 -1
  234. package/dist/templates/code/panel.js +34 -2
  235. package/dist/templates/code/panel.js.map +1 -1
  236. package/dist/templates/code/plate.d.ts +3 -1
  237. package/dist/templates/code/plate.d.ts.map +1 -1
  238. package/dist/templates/code/plate.js +11 -9
  239. package/dist/templates/code/plate.js.map +1 -1
  240. package/dist/templates/code/spans.js +1 -1
  241. package/dist/templates/code/spans.js.map +1 -1
  242. package/dist/templates/code/width.d.ts +10 -0
  243. package/dist/templates/code/width.d.ts.map +1 -0
  244. package/dist/templates/code/width.js +26 -0
  245. package/dist/templates/code/width.js.map +1 -0
  246. package/dist/templates/footer.d.ts +8 -0
  247. package/dist/templates/footer.d.ts.map +1 -1
  248. package/dist/templates/footer.js +11 -1
  249. package/dist/templates/footer.js.map +1 -1
  250. package/dist/templates/index.d.ts +1 -1
  251. package/dist/templates/index.d.ts.map +1 -1
  252. package/dist/templates/index.js +1 -1
  253. package/dist/templates/index.js.map +1 -1
  254. package/dist/templates/logo.d.ts +15 -0
  255. package/dist/templates/logo.d.ts.map +1 -0
  256. package/dist/templates/logo.js +30 -0
  257. package/dist/templates/logo.js.map +1 -0
  258. package/dist/templates/measure.d.ts +11 -0
  259. package/dist/templates/measure.d.ts.map +1 -0
  260. package/dist/templates/measure.js +11 -0
  261. package/dist/templates/measure.js.map +1 -0
  262. package/dist/templates/props.d.ts +2 -2
  263. package/dist/templates/props.js +2 -2
  264. package/dist/templates/text.d.ts +37 -0
  265. package/dist/templates/text.d.ts.map +1 -0
  266. package/dist/templates/text.js +26 -0
  267. package/dist/templates/text.js.map +1 -0
  268. package/dist/text/break.d.ts +11 -0
  269. package/dist/text/break.d.ts.map +1 -0
  270. package/dist/text/break.js +30 -0
  271. package/dist/text/break.js.map +1 -0
  272. package/dist/text/fit.d.ts +30 -0
  273. package/dist/text/fit.d.ts.map +1 -0
  274. package/dist/text/fit.js +29 -0
  275. package/dist/text/fit.js.map +1 -0
  276. package/dist/text/index.d.ts +5 -3
  277. package/dist/text/index.d.ts.map +1 -1
  278. package/dist/text/index.js +3 -2
  279. package/dist/text/index.js.map +1 -1
  280. package/dist/text/wrap.d.ts +17 -7
  281. package/dist/text/wrap.d.ts.map +1 -1
  282. package/dist/text/wrap.js +25 -17
  283. package/dist/text/wrap.js.map +1 -1
  284. package/dist/types.d.ts +161 -45
  285. package/dist/types.d.ts.map +1 -1
  286. package/dist/validate/index.d.ts +1 -1
  287. package/dist/validate/index.d.ts.map +1 -1
  288. package/dist/validate/index.js +3 -2
  289. package/dist/validate/index.js.map +1 -1
  290. package/dist/validate/keys.d.ts +19 -2
  291. package/dist/validate/keys.d.ts.map +1 -1
  292. package/dist/validate/keys.js +40 -3
  293. package/dist/validate/keys.js.map +1 -1
  294. package/dist/validate/suggest.d.ts.map +1 -1
  295. package/dist/validate/suggest.js +21 -3
  296. package/dist/validate/suggest.js.map +1 -1
  297. package/dist/validate/values.d.ts +2 -2
  298. package/dist/validate/values.d.ts.map +1 -1
  299. package/dist/validate/values.js +17 -3
  300. package/dist/validate/values.js.map +1 -1
  301. package/package.json +7 -1
@@ -2,14 +2,14 @@ import { open } from "node:fs/promises";
2
2
  import { pngSignature, stampKeyword } from "./chunk.js";
3
3
  /**
4
4
  * How much of a PNG to read when looking for a stamp. The stamp goes in
5
- * immediately after `IHDR`, so this only has to cover the header — reading
5
+ * immediately after `IHDR`, so this only has to cover the header. Reading
6
6
  * whole images just to compare a hash would defeat the point of skipping them.
7
7
  */
8
8
  const headBytes = 4096;
9
9
  /**
10
10
  * Find the stamp in the leading bytes of a PNG, or `undefined` if there is
11
- * none the image was written by something else, or by a Colophon that did
12
- * not stamp yet.
11
+ * none, meaning the image was written by something else, or by a Colophon
12
+ * that did not stamp yet.
13
13
  */
14
14
  function findStamp(head) {
15
15
  if (!head.subarray(0, pngSignature.length).equals(pngSignature)) {
@@ -39,7 +39,7 @@ function findStamp(head) {
39
39
  }
40
40
  /**
41
41
  * Read the stamp out of a PNG file. Returns `undefined` when the file is
42
- * missing, unreadable, not a PNG, or carries no stamp all of which mean the
42
+ * missing, unreadable, not a PNG, or carries no stamp, all of which mean the
43
43
  * image cannot be shown to be up to date, so it should be rendered again.
44
44
  */
45
45
  export async function readPngStamp(file) {
@@ -0,0 +1,17 @@
1
+ import type { ImageAsset, MeasureText, ResolvedConfig } from "../types.js";
2
+ import type { FooterPlacement } from "./footer.js";
3
+ /** Where the attribution line goes: a footer placement, plus room to lay it out. */
4
+ export interface AttributionPlacement extends FooterPlacement {
5
+ /** Left edge and width of the content area the line is set within. */
6
+ readonly left: number;
7
+ readonly width: number;
8
+ }
9
+ /**
10
+ * The footer line, with the post's avatar before it.
11
+ *
12
+ * Both belong to the same idea, which is who made this, so they are drawn as
13
+ * one line rather than tucked into separate corners. Without an avatar this is
14
+ * the footer exactly as it was, down to the byte.
15
+ */
16
+ export declare function attribution(config: ResolvedConfig, placement: AttributionPlacement, avatar: ImageAsset | undefined, measure: MeasureText): string;
17
+ //# sourceMappingURL=attribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../../src/templates/attribution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAYnD,oFAAoF;AACpF,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC3D,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,oBAAoB,EAC/B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,OAAO,EAAE,WAAW,GACnB,MAAM,CAqCR"}
@@ -0,0 +1,39 @@
1
+ import { image, measureIn, row } from "../layout/index.js";
2
+ import { footerElement, hasFooter } from "./footer.js";
3
+ /** The avatar's diameter, as a multiple of the footer's font size. */
4
+ const avatarScale = 1.9;
5
+ /** Where a circular avatar's centre sits above the footer's baseline. */
6
+ const avatarRise = 0.34;
7
+ /** Unique within one image, which is as many avatars as there are. */
8
+ const avatarId = "colophon-avatar";
9
+ /**
10
+ * The footer line, with the post's avatar before it.
11
+ *
12
+ * Both belong to the same idea, which is who made this, so they are drawn as
13
+ * one line rather than tucked into separate corners. Without an avatar this is
14
+ * the footer exactly as it was, down to the byte.
15
+ */
16
+ export function attribution(config, placement, avatar, measure) {
17
+ if (avatar === undefined) {
18
+ return footerElement(config, placement);
19
+ }
20
+ const { fontSize } = placement;
21
+ const size = Math.round(fontSize * avatarScale);
22
+ const text = hasFooter(config) ? (config.footer ?? "") : "";
23
+ const gap = text === "" ? 0 : Math.round(fontSize * 0.5);
24
+ const textWidth = text === ""
25
+ ? 0
26
+ : measureIn(measure, config.fontFamily, 500)(text, fontSize);
27
+ // Only the horizontal placement comes from the row. The baseline is the one
28
+ // the template asked for, so a footer with no avatar and a footer with one
29
+ // sit at the same height.
30
+ const [portrait, label] = row([{ size }, { size: Math.round(textWidth), gapBefore: gap }], { x: placement.left, y: placement.y, width: placement.width, height: size }, placement.anchor === "middle" ? "centre" : "start");
31
+ const top = Math.round(placement.y - fontSize * avatarRise - size / 2);
32
+ return (image({ x: portrait?.x ?? placement.left, y: top, width: size, height: size }, avatar.href, { fit: "cover", radius: Math.round(size / 2), id: avatarId }) +
33
+ footerElement(config, {
34
+ ...placement,
35
+ x: label?.x ?? placement.left,
36
+ anchor: "start",
37
+ }));
38
+ }
39
+ //# sourceMappingURL=attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/templates/attribution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,sEAAsE;AACtE,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,yEAAyE;AACzE,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,sEAAsE;AACtE,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AASnC;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,MAAsB,EACtB,SAA+B,EAC/B,MAA8B,EAC9B,OAAoB;IAEpB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;IACzD,MAAM,SAAS,GACb,IAAI,KAAK,EAAE;QACT,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEjE,4EAA4E;IAC5E,2EAA2E;IAC3E,0BAA0B;IAC1B,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,GAAG,CAC3B,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAC3D,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAC3E,SAAS,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CACnD,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IAEvE,OAAO,CACL,KAAK,CACH,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EACvE,MAAM,CAAC,IAAI,EACX,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAC7D;QACD,aAAa,CAAC,MAAM,EAAE;YACpB,GAAG,SAAS;YACZ,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI;YAC7B,MAAM,EAAE,OAAO;SAChB,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/badge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAqBR"}
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/badge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR"}
@@ -1,4 +1,4 @@
1
- import { textElement } from "../../text/index.js";
1
+ import { box, textElement } from "../../layout/index.js";
2
2
  /**
3
3
  * The corner badge: a rounded plate with the badge text on it, sized from the
4
4
  * plate height so it scales with the image rather than the text length.
@@ -7,10 +7,7 @@ export function renderBadge(badge, fontFamily, brand, pad, height) {
7
7
  const fontSize = Math.round(height * 0.6);
8
8
  const padX = Math.round(height * 0.36);
9
9
  const width = Math.round(badge.text.length * fontSize * 0.64 + padX * 2);
10
- const radius = Math.round(height * 0.1);
11
- const rect = `<rect x="${String(pad)}" y="${String(pad)}"` +
12
- ` width="${String(width)}" height="${String(height)}"` +
13
- ` rx="${String(radius)}" fill="${badge.background ?? "#ffffff"}"/>`;
10
+ const plate = box({ x: pad, y: pad, width, height }, { radius: Math.round(height * 0.1), fill: badge.background ?? "#ffffff" });
14
11
  const text = textElement(badge.text, {
15
12
  x: pad + padX,
16
13
  y: pad + Math.round(height * 0.72),
@@ -19,6 +16,6 @@ export function renderBadge(badge, fontFamily, brand, pad, height) {
19
16
  fontWeight: 900,
20
17
  fill: badge.color ?? brand,
21
18
  });
22
- return rect + text;
19
+ return plate + text;
23
20
  }
24
21
  //# sourceMappingURL=badge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge.js","sourceRoot":"","sources":["../../../src/templates/banner/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,KAAY,EACZ,UAAkB,EAClB,KAAa,EACb,GAAW,EACX,MAAc;IAEd,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAExC,MAAM,IAAI,GACR,YAAY,MAAM,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,GAAG,CAAC,GAAG;QAC7C,WAAW,MAAM,CAAC,KAAK,CAAC,aAAa,MAAM,CAAC,MAAM,CAAC,GAAG;QACtD,QAAQ,MAAM,CAAC,MAAM,CAAC,WAAW,KAAK,CAAC,UAAU,IAAI,SAAS,KAAK,CAAC;IAEtE,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE;QACnC,CAAC,EAAE,GAAG,GAAG,IAAI;QACb,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;QAClC,UAAU;QACV,QAAQ;QACR,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK;KAC3B,CAAC,CAAC;IAEH,OAAO,IAAI,GAAG,IAAI,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"badge.js","sourceRoot":"","sources":["../../../src/templates/banner/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,KAAY,EACZ,UAAkB,EAClB,KAAa,EACb,GAAW,EACX,MAAc;IAEd,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IAEzE,MAAM,KAAK,GAAG,GAAG,CACf,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EACjC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,IAAI,SAAS,EAAE,CAC1E,CAAC;IAEF,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE;QACnC,CAAC,EAAE,GAAG,GAAG,IAAI;QACb,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;QAClC,UAAU;QACV,QAAQ;QACR,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK;KAC3B,CAAC,CAAC;IAEH,OAAO,KAAK,GAAG,IAAI,CAAC;AACtB,CAAC"}
@@ -4,6 +4,9 @@ import type { Template } from "../../types.js";
4
4
  * version and wrapped subtitle, an optional corner badge, and an optional
5
5
  * footer. This is the configurable descendant of the original `npm_package`
6
6
  * layout.
7
+ *
8
+ * A logo goes in the opposite corner to the badge, which is the corner the
9
+ * left-aligned text leaves free, and the avatar sits with the footer.
7
10
  */
8
11
  export declare const bannerTemplate: Template;
9
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAMhE;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,QA6E5B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAOhE;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,EAAE,QAmF5B,CAAC"}
@@ -1,6 +1,8 @@
1
- import { layoutStack, textElement } from "../../text/index.js";
2
- import { footerElement, hasFooter } from "../footer.js";
3
- import { optionalString } from "../props.js";
1
+ import { drawLines, inset } from "../../layout/index.js";
2
+ import { optionalString } from "../../props.js";
3
+ import { attribution } from "../attribution.js";
4
+ import { footerBaseline, hasFooter } from "../footer.js";
5
+ import { logoElement, logoRect } from "../logo.js";
4
6
  import { renderBadge } from "./badge.js";
5
7
  import { bannerLines } from "./lines.js";
6
8
  /**
@@ -8,59 +10,59 @@ import { bannerLines } from "./lines.js";
8
10
  * version and wrapped subtitle, an optional corner badge, and an optional
9
11
  * footer. This is the configurable descendant of the original `npm_package`
10
12
  * layout.
13
+ *
14
+ * A logo goes in the opposite corner to the badge, which is the corner the
15
+ * left-aligned text leaves free, and the avatar sits with the footer.
11
16
  */
12
17
  export const bannerTemplate = {
13
18
  name: "banner",
14
- render({ props, config, dimensions }) {
19
+ render({ props, config, dimensions, measure, logo, avatar, }) {
15
20
  const { width, height } = dimensions;
16
21
  const { fontFamily } = config;
17
22
  const pad = Math.round(width * 0.075);
18
- const contentWidth = width - pad * 2;
19
- const subtitle = optionalString(props.subtitle);
20
- const hasSubtitle = subtitle !== undefined && subtitle !== "";
21
- const titleFs = Math.round(height * (hasSubtitle ? 0.078 : 0.092));
22
23
  const footerFs = Math.round(height * 0.034);
23
24
  const badgeHeight = Math.round(height * 0.072);
25
+ const mark = logoRect(logo, dimensions, pad, "start");
26
+ const subtitle = optionalString(props.subtitle);
27
+ const hasSubtitle = subtitle !== undefined && subtitle !== "";
28
+ // The text sits between whatever the marks along the top and the footer
29
+ // along the bottom leave behind.
30
+ const topMark = Math.max(config.badge === undefined ? 0 : badgeHeight, mark?.height ?? 0);
31
+ const area = inset({ x: 0, y: 0, width, height }, {
32
+ top: pad + (topMark === 0 ? 0 : topMark + Math.round(height * 0.03)),
33
+ right: pad,
34
+ left: pad,
35
+ bottom: pad +
36
+ (hasFooter(config) || avatar !== undefined
37
+ ? footerFs + Math.round(height * 0.02)
38
+ : 0),
39
+ });
24
40
  const lines = bannerLines(props, {
25
41
  height,
26
- contentWidth,
27
- titleFs,
42
+ contentWidth: area.width,
43
+ titleFs: Math.round(height * (hasSubtitle ? 0.078 : 0.092)),
28
44
  versionFs: Math.round(height * 0.04),
29
45
  subFs: Math.round(height * 0.05),
46
+ measure,
47
+ fontFamily,
30
48
  });
31
- const top = pad +
32
- (config.badge === undefined
33
- ? 0
34
- : badgeHeight + Math.round(height * 0.03));
35
- const bottom = height -
36
- pad -
37
- (hasFooter(config) ? footerFs + Math.round(height * 0.02) : 0);
38
- const placed = layoutStack(lines.map((line) => ({
39
- fontSize: line.fontSize,
40
- lineHeight: 1.15,
41
- ...(line.gapBefore !== undefined && { gapBefore: line.gapBefore }),
42
- })), top, bottom);
43
- const body = lines
44
- .map((line, index) => textElement(line.text, {
45
- x: pad,
46
- y: placed[index]?.y ?? top,
49
+ const body = drawLines(lines, area, {
47
50
  fontFamily,
48
- fontSize: line.fontSize,
49
- fontWeight: line.fontWeight,
50
51
  fill: config.colors.foreground,
51
- fillOpacity: line.opacity,
52
- }))
53
- .join("");
52
+ lineHeight: 1.28,
53
+ });
54
54
  const badge = config.badge === undefined
55
55
  ? ""
56
56
  : renderBadge(config.badge, fontFamily, config.colors.brand, pad, badgeHeight);
57
- const footer = footerElement(config, {
57
+ const footer = attribution(config, {
58
58
  x: pad,
59
- y: height - pad,
59
+ y: footerBaseline(height, pad, footerFs),
60
60
  fontSize: footerFs,
61
61
  opacity: 0.78,
62
- });
63
- return badge + body + footer;
62
+ left: pad,
63
+ width: width - pad * 2,
64
+ }, avatar, measure);
65
+ return badge + logoElement(logo, mark) + body + footer;
64
66
  },
65
67
  };
66
68
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/banner/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/banner/index.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,22 @@
1
- import type { MetaImageProps } from "../../types.js";
1
+ import type { MeasureText, MetaImageProps } from "../../types.js";
2
+ import type { TextLine } from "../../layout/index.js";
2
3
  /**
3
- * One line of the banner's text block, with the weight and opacity that say
4
- * which of the title, version and subtitle groups it belongs to.
4
+ * The font sizes the banner's text is drawn at, all keyed to image height,
5
+ * along with the space it has and how to measure text into it.
5
6
  */
6
- export interface BannerLine {
7
- readonly text: string;
8
- readonly fontSize: number;
9
- readonly fontWeight: number;
10
- readonly opacity: number;
11
- readonly gapBefore?: number;
12
- }
13
- /** The font sizes the banner's text is drawn at, all keyed to image height. */
14
7
  export interface BannerSizes {
15
8
  readonly height: number;
16
9
  readonly contentWidth: number;
17
10
  readonly titleFs: number;
18
11
  readonly versionFs: number;
19
12
  readonly subFs: number;
13
+ readonly measure: MeasureText;
14
+ readonly fontFamily: string;
20
15
  }
21
16
  /**
22
17
  * The banner's text block: the wrapped title, an optional version, and the
23
18
  * wrapped subtitle. Extra breathing room goes before the version and subtitle
24
19
  * groups so the three do not read as one squashed block.
25
20
  */
26
- export declare function bannerLines(props: MetaImageProps, sizes: BannerSizes): BannerLine[];
21
+ export declare function bannerLines(props: MetaImageProps, sizes: BannerSizes): TextLine[];
27
22
  //# sourceMappingURL=lines.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/lines.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMrD;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,WAAW,GACjB,UAAU,EAAE,CA+Cd"}
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAStD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,WAAW,GACjB,QAAQ,EAAE,CAuBZ"}
@@ -1,46 +1,35 @@
1
- import { estimateCharsPerLine, wrapText } from "../../text/index.js";
2
- import { optionalString } from "../props.js";
1
+ import { blockLines } from "../../layout/index.js";
2
+ import { versionLines } from "./version.js";
3
3
  const maxTitleLines = 3;
4
4
  const maxSubtitleLines = 4;
5
+ const titleFloor = 0.62;
6
+ const subtitleFloor = 0.8;
5
7
  /**
6
8
  * The banner's text block: the wrapped title, an optional version, and the
7
9
  * wrapped subtitle. Extra breathing room goes before the version and subtitle
8
10
  * groups so the three do not read as one squashed block.
9
11
  */
10
12
  export function bannerLines(props, sizes) {
11
- const { height, contentWidth, titleFs, versionFs, subFs } = sizes;
12
- const title = optionalString(props.title) ?? "";
13
- const subtitle = optionalString(props.subtitle);
14
- const version = optionalString(props.version);
15
- const lines = wrapText(title, estimateCharsPerLine(contentWidth, titleFs, 0.6))
16
- .slice(0, maxTitleLines)
17
- .map((text) => ({
18
- text,
19
- fontSize: titleFs,
20
- fontWeight: 800,
21
- opacity: 0.98,
22
- }));
23
- if (version !== undefined && version !== "") {
24
- lines.push({
25
- text: `v${version}`,
26
- fontSize: versionFs,
27
- fontWeight: 700,
28
- opacity: 0.85,
29
- gapBefore: Math.round(height * 0.03),
30
- });
31
- }
32
- const subtitleLines = subtitle === undefined || subtitle === ""
33
- ? []
34
- : wrapText(subtitle, estimateCharsPerLine(contentWidth, subFs, 0.55)).slice(0, maxSubtitleLines);
35
- for (const [index, text] of subtitleLines.entries()) {
36
- lines.push({
37
- text,
38
- fontSize: subFs,
13
+ const { height, contentWidth, measure, fontFamily } = sizes;
14
+ return [
15
+ ...blockLines(props.title, measure, fontFamily, {
16
+ maxWidth: contentWidth,
17
+ maxLines: maxTitleLines,
18
+ fontSize: sizes.titleFs,
19
+ floor: titleFloor,
20
+ fontWeight: 800,
21
+ opacity: 0.98,
22
+ }),
23
+ ...versionLines(props, sizes),
24
+ ...blockLines(props.subtitle, measure, fontFamily, {
25
+ maxWidth: contentWidth,
26
+ maxLines: maxSubtitleLines,
27
+ fontSize: sizes.subFs,
28
+ floor: subtitleFloor,
39
29
  fontWeight: 500,
40
30
  opacity: 0.86,
41
- ...(index === 0 && { gapBefore: Math.round(height * 0.045) }),
42
- });
43
- }
44
- return lines;
31
+ gapBefore: Math.round(height * 0.045),
32
+ }),
33
+ ];
45
34
  }
46
35
  //# sourceMappingURL=lines.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lines.js","sourceRoot":"","sources":["../../../src/templates/banner/lines.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAuB3B;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,KAAqB,EACrB,KAAkB;IAElB,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IAClE,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAChD,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE9C,MAAM,KAAK,GAAiB,QAAQ,CAClC,KAAK,EACL,oBAAoB,CAAC,YAAY,EAAE,OAAO,EAAE,GAAG,CAAC,CACjD;SACE,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC;SACvB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACd,IAAI;QACJ,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,GAAG;QACf,OAAO,EAAE,IAAI;KACd,CAAC,CAAC,CAAC;IAEN,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,IAAI,OAAO,EAAE;YACnB,QAAQ,EAAE,SAAS;YACnB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,aAAa,GACjB,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE;QACvC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,QAAQ,CACN,QAAQ,EACR,oBAAoB,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAChD,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAEnC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI;YACJ,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;YACb,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"lines.js","sourceRoot":"","sources":["../../../src/templates/banner/lines.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,aAAa,GAAG,GAAG,CAAC;AAgB1B;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,KAAqB,EACrB,KAAkB;IAElB,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAE5D,OAAO;QACL,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE;YAC9C,QAAQ,EAAE,YAAY;YACtB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,KAAK,CAAC,OAAO;YACvB,KAAK,EAAE,UAAU;YACjB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;SACd,CAAC;QACF,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC;QAC7B,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE;YACjD,QAAQ,EAAE,YAAY;YACtB,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,KAAK,CAAC,KAAK;YACrB,KAAK,EAAE,aAAa;YACpB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;SACtC,CAAC;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { MetaImageProps } from "../../types.js";
2
+ import type { TextLine } from "../../layout/index.js";
3
+ import type { BannerSizes } from "./lines.js";
4
+ /**
5
+ * The version line, or nothing where there is no version. It is never wrapped
6
+ * or shrunk: a version string that needed either would not be one.
7
+ */
8
+ export declare function versionLines(props: MetaImageProps, sizes: BannerSizes): readonly TextLine[];
9
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/version.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,WAAW,GACjB,SAAS,QAAQ,EAAE,CAgBrB"}
@@ -0,0 +1,21 @@
1
+ import { optionalString } from "../../props.js";
2
+ /**
3
+ * The version line, or nothing where there is no version. It is never wrapped
4
+ * or shrunk: a version string that needed either would not be one.
5
+ */
6
+ export function versionLines(props, sizes) {
7
+ const version = optionalString(props.version);
8
+ if (version === undefined || version === "") {
9
+ return [];
10
+ }
11
+ return [
12
+ {
13
+ text: `v${version}`,
14
+ fontSize: sizes.versionFs,
15
+ fontWeight: 700,
16
+ opacity: 0.85,
17
+ gapBefore: Math.round(sizes.height * 0.03),
18
+ },
19
+ ];
20
+ }
21
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/templates/banner/version.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIhD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAqB,EACrB,KAAkB;IAElB,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE9C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QAC5C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO;QACL;YACE,IAAI,EAAE,IAAI,OAAO,EAAE;YACnB,QAAQ,EAAE,KAAK,CAAC,SAAS;YACzB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;SAC3C;KACF,CAAC;AACJ,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import type { Template } from "../../types.js";
2
2
  /**
3
3
  * Minimal "card" template: a centred title with an optional subtitle. No
4
- * badge or version a clean, quieter alternative to `banner`.
4
+ * badge or version, so it is a quieter alternative to `banner`.
5
+ *
6
+ * A logo goes above the title, centred like everything else here, and the
7
+ * avatar sits with the footer along the bottom.
5
8
  */
6
9
  export declare const cardTemplate: Template;
7
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/card/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAIhE;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,QAqD1B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/card/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAMhE;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,EAAE,QA8D1B,CAAC"}
@@ -1,43 +1,55 @@
1
- import { layoutStack, textElement } from "../../text/index.js";
2
- import { footerElement, hasFooter } from "../footer.js";
1
+ import { drawLines, inset } from "../../layout/index.js";
2
+ import { attribution } from "../attribution.js";
3
+ import { footerBaseline, hasFooter } from "../footer.js";
4
+ import { logoElement, logoRect } from "../logo.js";
3
5
  import { cardLines } from "./lines.js";
4
6
  /**
5
7
  * Minimal "card" template: a centred title with an optional subtitle. No
6
- * badge or version a clean, quieter alternative to `banner`.
8
+ * badge or version, so it is a quieter alternative to `banner`.
9
+ *
10
+ * A logo goes above the title, centred like everything else here, and the
11
+ * avatar sits with the footer along the bottom.
7
12
  */
8
13
  export const cardTemplate = {
9
14
  name: "card",
10
- render({ props, config, dimensions }) {
15
+ render({ props, config, dimensions, measure, logo, avatar, }) {
11
16
  const { width, height } = dimensions;
12
17
  const pad = Math.round(width * 0.09);
13
- const centreX = Math.round(width / 2);
14
- const titleFs = Math.round(height * 0.1);
15
18
  const footerFs = Math.round(height * 0.032);
16
- const lines = cardLines(props, width - pad * 2, titleFs, Math.round(height * 0.045));
17
- const bottom = height -
18
- pad -
19
- (hasFooter(config) ? footerFs + Math.round(height * 0.02) : 0);
20
- const placed = layoutStack(lines.map((line) => ({ fontSize: line.fontSize, lineHeight: 1.2 })), pad, bottom);
21
- const body = lines
22
- .map((line, index) => textElement(line.text, {
23
- x: centreX,
24
- y: placed[index]?.y ?? pad,
19
+ const mark = logoRect(logo, dimensions, pad, "middle");
20
+ const area = inset({ x: 0, y: 0, width, height }, {
21
+ top: pad + (mark === undefined ? 0 : mark.height + pad / 2),
22
+ right: pad,
23
+ left: pad,
24
+ bottom: pad +
25
+ (hasFooter(config) || avatar !== undefined
26
+ ? footerFs + Math.round(height * 0.02)
27
+ : 0),
28
+ });
29
+ const lines = cardLines(props, {
30
+ measure,
31
+ fontFamily: config.fontFamily,
32
+ contentWidth: area.width,
33
+ titleFs: Math.round(height * 0.1),
34
+ subFs: Math.round(height * 0.045),
35
+ height,
36
+ });
37
+ const body = drawLines(lines, area, {
25
38
  fontFamily: config.fontFamily,
26
- fontSize: line.fontSize,
27
- fontWeight: line.fontWeight,
28
39
  fill: config.colors.foreground,
29
- fillOpacity: line.opacity,
40
+ lineHeight: 1.28,
30
41
  anchor: "middle",
31
- }))
32
- .join("");
33
- const footer = footerElement(config, {
34
- x: centreX,
35
- y: height - pad,
42
+ });
43
+ const footer = attribution(config, {
44
+ x: Math.round(width / 2),
45
+ y: footerBaseline(height, pad, footerFs),
36
46
  fontSize: footerFs,
37
47
  opacity: 0.75,
38
48
  anchor: "middle",
39
- });
40
- return body + footer;
49
+ left: pad,
50
+ width: width - pad * 2,
51
+ }, avatar, measure);
52
+ return logoElement(logo, mark) + body + footer;
41
53
  },
42
54
  };
43
55
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,IAAI,EAAE,MAAM;IACZ,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAmB;QACnD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAEtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QAE5C,MAAM,KAAK,GAAG,SAAS,CACrB,KAAK,EACL,KAAK,GAAG,GAAG,GAAG,CAAC,EACf,OAAO,EACP,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAC3B,CAAC;QAEF,MAAM,MAAM,GACV,MAAM;YACN,GAAG;YACH,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjE,MAAM,MAAM,GAAG,WAAW,CACxB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EACnE,GAAG,EACH,MAAM,CACP,CAAC;QAEF,MAAM,IAAI,GAAG,KAAK;aACf,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACnB,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE;YACrB,CAAC,EAAE,OAAO;YACV,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,GAAG;YAC1B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;YAC9B,WAAW,EAAE,IAAI,CAAC,OAAO;YACzB,MAAM,EAAE,QAAQ;SACjB,CAAC,CACH;aACA,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE;YACnC,CAAC,EAAE,OAAO;YACV,CAAC,EAAE,MAAM,GAAG,GAAG;YACf,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QAEH,OAAO,IAAI,GAAG,MAAM,CAAC;IACvB,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,IAAI,EAAE,MAAM;IACZ,MAAM,CAAC,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,IAAI,EACJ,MAAM,GACU;QAChB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,KAAK,CAChB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAC7B;YACE,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC;YAC3D,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,GAAG;YACT,MAAM,EACJ,GAAG;gBACH,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,SAAS;oBACxC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;oBACtC,CAAC,CAAC,CAAC,CAAC;SACT,CACF,CAAC;QAEF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE;YAC7B,OAAO;YACP,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;YACjC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACjC,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;YAClC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;YAC9B,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,WAAW,CACxB,MAAM,EACN;YACE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YACxB,CAAC,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC;YACxC,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,GAAG;YACT,KAAK,EAAE,KAAK,GAAG,GAAG,GAAG,CAAC;SACvB,EACD,MAAM,EACN,OAAO,CACR,CAAC;QAEF,OAAO,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;IACjD,CAAC;CACF,CAAC"}
@@ -1,17 +1,21 @@
1
- import type { MetaImageProps } from "../../types.js";
2
- /**
3
- * One line of the card's centred text block.
4
- */
5
- export interface CardLine {
6
- readonly text: string;
7
- readonly fontSize: number;
8
- readonly fontWeight: number;
9
- readonly opacity: number;
1
+ import type { MeasureText, MetaImageProps } from "../../types.js";
2
+ import type { TextLine } from "../../layout/index.js";
3
+ /** The space the card's text has, and how to measure text into it. */
4
+ export interface CardText {
5
+ readonly measure: MeasureText;
6
+ readonly fontFamily: string;
7
+ readonly contentWidth: number;
8
+ readonly titleFs: number;
9
+ readonly subFs: number;
10
+ readonly height: number;
10
11
  }
11
12
  /**
12
- * The card's text block: the wrapped title, then the wrapped subtitle. No
13
- * gaps between the groups — the card is the quieter layout, and the change of
14
- * size and weight is enough to separate them.
13
+ * The card's text block: the wrapped title, then the wrapped subtitle.
14
+ *
15
+ * The gap before the subtitle is smaller than the banner's, because the card
16
+ * has only the two groups and they belong together. It is not nothing, though:
17
+ * a title that wraps ends on a line the subtitle would otherwise sit straight
18
+ * underneath, and the change of size and weight alone does not separate them.
15
19
  */
16
- export declare function cardLines(props: MetaImageProps, contentWidth: number, titleFs: number, subFs: number): CardLine[];
20
+ export declare function cardLines(props: MetaImageProps, text: CardText): TextLine[];
17
21
  //# sourceMappingURL=lines.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/card/lines.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMrD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,cAAc,EACrB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,QAAQ,EAAE,CA+BZ"}
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/card/lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAQtD,sEAAsE;AACtE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAsB3E"}