@kensio/colophon 2.13.0 → 2.14.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 (133) hide show
  1. package/README.md +14 -3
  2. package/dist/config/defaults.d.ts +77 -6
  3. package/dist/config/defaults.d.ts.map +1 -1
  4. package/dist/config/defaults.js +69 -6
  5. package/dist/config/defaults.js.map +1 -1
  6. package/dist/config/index.d.ts.map +1 -1
  7. package/dist/config/index.js +2 -0
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/config/resolve.d.ts +13 -0
  10. package/dist/config/resolve.d.ts.map +1 -1
  11. package/dist/config/resolve.js +14 -8
  12. package/dist/config/resolve.js.map +1 -1
  13. package/dist/config/safe-area.d.ts +27 -0
  14. package/dist/config/safe-area.d.ts.map +1 -0
  15. package/dist/config/safe-area.js +81 -0
  16. package/dist/config/safe-area.js.map +1 -0
  17. package/dist/config/size.d.ts.map +1 -1
  18. package/dist/config/size.js +1 -0
  19. package/dist/config/size.js.map +1 -1
  20. package/dist/core/index.d.ts +1 -1
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js.map +1 -1
  23. package/dist/fonts/bundled.d.ts +38 -0
  24. package/dist/fonts/bundled.d.ts.map +1 -0
  25. package/dist/fonts/bundled.js +29 -0
  26. package/dist/fonts/bundled.js.map +1 -0
  27. package/dist/fonts/index.d.ts +1 -0
  28. package/dist/fonts/index.d.ts.map +1 -1
  29. package/dist/fonts/index.js +1 -0
  30. package/dist/fonts/index.js.map +1 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/measure/faces.d.ts.map +1 -1
  35. package/dist/measure/faces.js +29 -5
  36. package/dist/measure/faces.js.map +1 -1
  37. package/dist/measure/index.d.ts.map +1 -1
  38. package/dist/measure/index.js +0 -0
  39. package/dist/measure/index.js.map +1 -1
  40. package/dist/platform/bundled-fonts.browser.d.ts +16 -0
  41. package/dist/platform/bundled-fonts.browser.d.ts.map +1 -0
  42. package/dist/platform/bundled-fonts.browser.js +17 -0
  43. package/dist/platform/bundled-fonts.browser.js.map +1 -0
  44. package/dist/platform/bundled-fonts.node.d.ts +18 -0
  45. package/dist/platform/bundled-fonts.node.d.ts.map +1 -0
  46. package/dist/platform/bundled-fonts.node.js +49 -0
  47. package/dist/platform/bundled-fonts.node.js.map +1 -0
  48. package/dist/render/rasterise.d.ts.map +1 -1
  49. package/dist/render/rasterise.js +8 -3
  50. package/dist/render/rasterise.js.map +1 -1
  51. package/dist/templates/article/index.js +1 -1
  52. package/dist/templates/article/index.js.map +1 -1
  53. package/dist/templates/banner/badge.d.ts +8 -1
  54. package/dist/templates/banner/badge.d.ts.map +1 -1
  55. package/dist/templates/banner/badge.js +8 -4
  56. package/dist/templates/banner/badge.js.map +1 -1
  57. package/dist/templates/banner/index.d.ts.map +1 -1
  58. package/dist/templates/banner/index.js +10 -25
  59. package/dist/templates/banner/index.js.map +1 -1
  60. package/dist/templates/bottom.d.ts +1 -1
  61. package/dist/templates/bottom.d.ts.map +1 -1
  62. package/dist/templates/bottom.js +5 -5
  63. package/dist/templates/bottom.js.map +1 -1
  64. package/dist/templates/card/index.d.ts.map +1 -1
  65. package/dist/templates/card/index.js +9 -25
  66. package/dist/templates/card/index.js.map +1 -1
  67. package/dist/templates/cover/index.d.ts +21 -0
  68. package/dist/templates/cover/index.d.ts.map +1 -0
  69. package/dist/templates/cover/index.js +67 -0
  70. package/dist/templates/cover/index.js.map +1 -0
  71. package/dist/templates/cover/lines.d.ts +21 -0
  72. package/dist/templates/cover/lines.d.ts.map +1 -0
  73. package/dist/templates/cover/lines.js +73 -0
  74. package/dist/templates/cover/lines.js.map +1 -0
  75. package/dist/templates/cover/lockup.d.ts +47 -0
  76. package/dist/templates/cover/lockup.d.ts.map +1 -0
  77. package/dist/templates/cover/lockup.js +71 -0
  78. package/dist/templates/cover/lockup.js.map +1 -0
  79. package/dist/templates/docs/index.js +3 -3
  80. package/dist/templates/docs/index.js.map +1 -1
  81. package/dist/templates/event/index.js +3 -3
  82. package/dist/templates/event/index.js.map +1 -1
  83. package/dist/templates/footer.d.ts +3 -0
  84. package/dist/templates/footer.d.ts.map +1 -1
  85. package/dist/templates/footer.js +16 -1
  86. package/dist/templates/footer.js.map +1 -1
  87. package/dist/templates/frame.d.ts +27 -3
  88. package/dist/templates/frame.d.ts.map +1 -1
  89. package/dist/templates/frame.js +19 -7
  90. package/dist/templates/frame.js.map +1 -1
  91. package/dist/templates/index.d.ts +1 -0
  92. package/dist/templates/index.d.ts.map +1 -1
  93. package/dist/templates/index.js +3 -0
  94. package/dist/templates/index.js.map +1 -1
  95. package/dist/templates/logo.d.ts +6 -2
  96. package/dist/templates/logo.d.ts.map +1 -1
  97. package/dist/templates/logo.js +10 -6
  98. package/dist/templates/logo.js.map +1 -1
  99. package/dist/templates/photo/index.d.ts.map +1 -1
  100. package/dist/templates/photo/index.js +9 -4
  101. package/dist/templates/photo/index.js.map +1 -1
  102. package/dist/templates/quote/index.js +2 -2
  103. package/dist/templates/quote/index.js.map +1 -1
  104. package/dist/templates/release/index.js +3 -3
  105. package/dist/templates/release/index.js.map +1 -1
  106. package/dist/templates/stat/index.js +3 -3
  107. package/dist/templates/stat/index.js.map +1 -1
  108. package/dist/templates/thumbnail/index.js +3 -3
  109. package/dist/templates/thumbnail/index.js.map +1 -1
  110. package/dist/templates/wordmark/index.js +2 -2
  111. package/dist/templates/wordmark/index.js.map +1 -1
  112. package/dist/types.d.ts +49 -0
  113. package/dist/types.d.ts.map +1 -1
  114. package/dist/validate/collect.d.ts.map +1 -1
  115. package/dist/validate/collect.js +2 -1
  116. package/dist/validate/collect.js.map +1 -1
  117. package/dist/validate/keys.d.ts +2 -0
  118. package/dist/validate/keys.d.ts.map +1 -1
  119. package/dist/validate/keys.js +9 -0
  120. package/dist/validate/keys.js.map +1 -1
  121. package/dist/validate/overrides.d.ts.map +1 -1
  122. package/dist/validate/overrides.js +2 -1
  123. package/dist/validate/overrides.js.map +1 -1
  124. package/fonts/JetBrainsMono-LICENSE.txt +93 -0
  125. package/fonts/JetBrainsMono_400Regular.ttf +0 -0
  126. package/fonts/JetBrainsMono_700Bold.ttf +0 -0
  127. package/fonts/Outfit-LICENSE.txt +93 -0
  128. package/fonts/Outfit_400Regular.ttf +0 -0
  129. package/fonts/Outfit_500Medium.ttf +0 -0
  130. package/fonts/Outfit_600SemiBold.ttf +0 -0
  131. package/fonts/Outfit_700Bold.ttf +0 -0
  132. package/fonts/Outfit_800ExtraBold.ttf +0 -0
  133. package/package.json +4 -2
@@ -0,0 +1,21 @@
1
+ import type { Template } from "../../types.js";
2
+ /**
3
+ * A profile cover: the mark beside the name, with a tagline under it.
4
+ *
5
+ * This is the header image at the top of a profile rather than a card attached
6
+ * to a post, so it is made once for a site and usually declared in
7
+ * `config.extra`. What makes it its own template rather than the `wordmark` at
8
+ * other proportions is the shape of the space: a cover is a strip somewhere
9
+ * between 2.6:1 and 6:1, and a layout that stacks a mark above a name has
10
+ * nothing left to set the name in.
11
+ *
12
+ * Every platform crops a cover and draws a circular avatar over one corner of
13
+ * it, so where the words may go is not the image. That is what `config.safeArea`
14
+ * describes and what the cover presets in `SIZE_PRESETS` carry, and by the time
15
+ * a template sees a frame it has already been applied. The one thing this
16
+ * template does about it is size its text from the room it actually has rather
17
+ * than from the image, which on a YouTube banner is the difference between 423
18
+ * pixels and 1440.
19
+ */
20
+ export declare const coverTemplate: Template;
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/cover/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAoBhE;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa,EAAE,QA0C3B,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { safeRect } from "../../config/safe-area.js";
2
+ import { drawLines } from "../../layout/index.js";
3
+ import { footerLine } from "../bottom.js";
4
+ import { contentArea, imageFrame } from "../frame.js";
5
+ import { coverLines } from "./lines.js";
6
+ import { linesWidth, lockup, markElement, markSpace } from "./lockup.js";
7
+ /**
8
+ * The margin, as a fraction of the frame's height rather than its width.
9
+ *
10
+ * A cover is a strip between about 2.6:1 and 6:1, so a margin taken from the
11
+ * width is a margin measured against the one dimension that has room to spare.
12
+ * On a LinkedIn Page cover the usual 7.5% of the width is 208px above and
13
+ * below a band 504px tall. The safe area has already done the horizontal work,
14
+ * which is the other half of why this is the axis that matters here.
15
+ */
16
+ const padScale = 0.09;
17
+ /** How the name and its tagline are stacked. */
18
+ const lineHeight = 1.15;
19
+ /**
20
+ * A profile cover: the mark beside the name, with a tagline under it.
21
+ *
22
+ * This is the header image at the top of a profile rather than a card attached
23
+ * to a post, so it is made once for a site and usually declared in
24
+ * `config.extra`. What makes it its own template rather than the `wordmark` at
25
+ * other proportions is the shape of the space: a cover is a strip somewhere
26
+ * between 2.6:1 and 6:1, and a layout that stacks a mark above a name has
27
+ * nothing left to set the name in.
28
+ *
29
+ * Every platform crops a cover and draws a circular avatar over one corner of
30
+ * it, so where the words may go is not the image. That is what `config.safeArea`
31
+ * describes and what the cover presets in `SIZE_PRESETS` carry, and by the time
32
+ * a template sees a frame it has already been applied. The one thing this
33
+ * template does about it is size its text from the room it actually has rather
34
+ * than from the image, which on a YouTube banner is the difference between 423
35
+ * pixels and 1440.
36
+ */
37
+ export const coverTemplate = {
38
+ name: "cover",
39
+ render({ props, config, dimensions, measure, logo, avatar, }) {
40
+ const { fontFamily } = config;
41
+ const safe = safeRect(dimensions, config.safeArea);
42
+ const frame = imageFrame(dimensions, config, avatar, {
43
+ pad: Math.round(safe.height * padScale),
44
+ });
45
+ const area = contentArea(frame);
46
+ const mark = markSpace(logo, area.height);
47
+ const lines = coverLines(props, {
48
+ measure,
49
+ fontFamily,
50
+ contentWidth: area.width - mark.width - mark.gap,
51
+ contentHeight: area.height,
52
+ });
53
+ const placed = lockup(area, mark, linesWidth(lines, measure, fontFamily));
54
+ const body = drawLines(lines, placed.text, {
55
+ fontFamily,
56
+ fill: config.colors.foreground,
57
+ lineHeight,
58
+ anchor: "start",
59
+ });
60
+ return (markElement(logo, placed.mark) +
61
+ body +
62
+ // Centred, because the lockup above it is, and a footer set against the
63
+ // left margin of a strip has nothing above it to line up with.
64
+ footerLine(config, frame, avatar, measure, "middle"));
65
+ },
66
+ };
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/cover/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEzE;;;;;;;;GAQG;AACH,MAAM,QAAQ,GAAG,IAAI,CAAC;AAEtB,gDAAgD;AAChD,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAa;IACrC,IAAI,EAAE,OAAO;IACb,MAAM,CAAC,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,IAAI,EACJ,MAAM,GACU;QAChB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE;YACnD,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;SACxC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QAEhC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE;YAC9B,OAAO;YACP,UAAU;YACV,YAAY,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG;YAChD,aAAa,EAAE,IAAI,CAAC,MAAM;SAC3B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;QAE1E,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE;YACzC,UAAU;YACV,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;YAC9B,UAAU;YACV,MAAM,EAAE,OAAO;SAChB,CAAC,CAAC;QAEH,OAAO,CACL,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC;YAC9B,IAAI;YACJ,wEAAwE;YACxE,+DAA+D;YAC/D,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CACrD,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { TextLine } from "../../layout/index.js";
2
+ import type { MeasureText, MetaImageProps } from "../../types.js";
3
+ /** The space the cover's text has, and how to measure it into it. */
4
+ export interface CoverText {
5
+ readonly measure: MeasureText;
6
+ readonly fontFamily: string;
7
+ readonly contentWidth: number;
8
+ /**
9
+ * The height the text is sized against, which is the content area's rather
10
+ * than the image's.
11
+ *
12
+ * Every other template takes its sizes from the image, and on a cover that
13
+ * is the wrong number by a wide margin: a YouTube banner is 1440 tall and
14
+ * the band anyone reads is 423 of it, so a title at a tenth of the image
15
+ * would be a third of the height of the part that is seen.
16
+ */
17
+ readonly contentHeight: number;
18
+ }
19
+ /** The name over its tagline, each fitted to the room the lockup has. */
20
+ export declare function coverLines(props: MetaImageProps, text: CoverText): TextLine[];
21
+ //# sourceMappingURL=lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/cover/lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA+BlE,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;;;;OAQG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AA4CD,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,EAAE,CAkB7E"}
@@ -0,0 +1,73 @@
1
+ import { blockLines, clampLine, measureIn } from "../../layout/index.js";
2
+ /**
3
+ * One line for the name, for the reason the `wordmark` has one: a name broken
4
+ * across two lines stops reading as a name. On a strip it is also the only
5
+ * arrangement that fits, since a second line of a title set to fill the band
6
+ * would be a second band.
7
+ */
8
+ const maxNameLines = 1;
9
+ const maxTaglineLines = 2;
10
+ /** The weights the two blocks are drawn at, and so measured at. */
11
+ const nameWeight = 800;
12
+ const taglineWeight = 500;
13
+ const nameFloor = 0.5;
14
+ const taglineFloor = 0.7;
15
+ /**
16
+ * The name's size, as a fraction of the room it has. It gives up a third of
17
+ * that where there is a tagline under it, which is what leaves the two
18
+ * reading as a pair rather than as one line with a caption squeezed beneath.
19
+ */
20
+ const nameScale = 0.48;
21
+ const nameWithTaglineScale = 0.3;
22
+ /** The tagline's size, and the clear space above it, both of the same room. */
23
+ const taglineScale = 0.15;
24
+ const taglineGapScale = 0.09;
25
+ /**
26
+ * The name as one line: shrunk until it fits, and cut with an ellipsis where
27
+ * even the floor is not small enough.
28
+ *
29
+ * Wrapping is what the fitting does at that point, and on a strip there is no
30
+ * second line to wrap onto. This is `wordmark`'s treatment of the same string,
31
+ * and it is here rather than shared because the two differ in the fitting
32
+ * around it rather than in this.
33
+ */
34
+ function nameLines(props, text, fontSize) {
35
+ const { measure, fontFamily, contentWidth } = text;
36
+ const name = props.title;
37
+ const [line] = blockLines(name, measure, fontFamily, {
38
+ maxWidth: contentWidth,
39
+ maxLines: maxNameLines,
40
+ fontSize,
41
+ floor: nameFloor,
42
+ fontWeight: nameWeight,
43
+ opacity: 1,
44
+ });
45
+ if (line === undefined || line.text === name) {
46
+ return line === undefined ? [] : [line];
47
+ }
48
+ return [
49
+ {
50
+ ...line,
51
+ text: clampLine(line.text, contentWidth, measureIn(measure, fontFamily, nameWeight), line.fontSize),
52
+ },
53
+ ];
54
+ }
55
+ /** The name over its tagline, each fitted to the room the lockup has. */
56
+ export function coverLines(props, text) {
57
+ const { measure, fontFamily, contentWidth, contentHeight } = text;
58
+ const tagline = blockLines(props.subtitle, measure, fontFamily, {
59
+ maxWidth: contentWidth,
60
+ maxLines: maxTaglineLines,
61
+ fontSize: Math.round(contentHeight * taglineScale),
62
+ floor: taglineFloor,
63
+ fontWeight: taglineWeight,
64
+ opacity: 0.85,
65
+ gapBefore: Math.round(contentHeight * taglineGapScale),
66
+ });
67
+ const scale = tagline.length === 0 ? nameScale : nameWithTaglineScale;
68
+ return [
69
+ ...nameLines(props, text, Math.round(contentHeight * scale)),
70
+ ...tagline,
71
+ ];
72
+ }
73
+ //# sourceMappingURL=lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.js","sourceRoot":"","sources":["../../../src/templates/cover/lines.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGzE;;;;;GAKG;AACH,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B,mEAAmE;AACnE,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,aAAa,GAAG,GAAG,CAAC;AAE1B,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB;;;;GAIG;AACH,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,+EAA+E;AAC/E,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,eAAe,GAAG,IAAI,CAAC;AAmB7B;;;;;;;;GAQG;AACH,SAAS,SAAS,CAChB,KAAqB,EACrB,IAAe,EACf,QAAgB;IAEhB,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IACnD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;IACzB,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE;QACnD,QAAQ,EAAE,YAAY;QACtB,QAAQ,EAAE,YAAY;QACtB,QAAQ;QACR,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,UAAU;QACtB,OAAO,EAAE,CAAC;KACX,CAAC,CAAC;IAEH,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC7C,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO;QACL;YACE,GAAG,IAAI;YACP,IAAI,EAAE,SAAS,CACb,IAAI,CAAC,IAAI,EACT,YAAY,EACZ,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,EAC1C,IAAI,CAAC,QAAQ,CACd;SACF;KACF,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,KAAqB,EAAE,IAAe;IAC/D,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAClE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE;QAC9D,QAAQ,EAAE,YAAY;QACtB,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,YAAY,CAAC;QAClD,KAAK,EAAE,YAAY;QACnB,UAAU,EAAE,aAAa;QACzB,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,eAAe,CAAC;KACvD,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC;IAEtE,OAAO;QACL,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,CAAC;QAC5D,GAAG,OAAO;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { Rect, TextLine } from "../../layout/index.js";
2
+ import type { ImageAsset, MeasureText } from "../../types.js";
3
+ /** The widest of a block of lines, which is how wide the block is. */
4
+ export declare function linesWidth(lines: readonly TextLine[], measure: MeasureText, fontFamily: string): number;
5
+ /** The room the mark takes along the row, including the gap after it. */
6
+ export interface Mark {
7
+ readonly width: number;
8
+ readonly gap: number;
9
+ }
10
+ /**
11
+ * How much of the row the mark claims, or nothing at all where the project has
12
+ * no logo, which is what takes the gap with it.
13
+ *
14
+ * The width and the gap come back together because the words need both before
15
+ * they can be fitted, and deriving either of them twice is how the room
16
+ * reserved stops matching the room used.
17
+ */
18
+ export declare function markSpace(logo: ImageAsset | undefined, contentHeight: number): Mark;
19
+ /** Where the mark and the words go: side by side, centred in the area. */
20
+ export interface Lockup {
21
+ readonly mark: Rect | undefined;
22
+ readonly text: Rect;
23
+ }
24
+ /**
25
+ * Set the mark beside the words and centre the pair.
26
+ *
27
+ * A cover is a strip between about 2.6:1 and 6:1, so the mark goes next to the
28
+ * name rather than above it as the `wordmark` template has it: stacked, three
29
+ * elements in 400px of height leave nothing legible. The words are then set
30
+ * from the left of the slot they were given rather than centred within it, so
31
+ * that a wrapped name lines up under itself and the whole lockup still sits in
32
+ * the middle.
33
+ *
34
+ * A project with no logo takes the same path with a mark of no width, which is
35
+ * one arrangement rather than two: `row` centres a single item exactly as it
36
+ * centres a pair.
37
+ */
38
+ export declare function lockup(area: Rect, mark: Mark, textWidth: number): Lockup;
39
+ /**
40
+ * The mark, centred down the slot it was given.
41
+ *
42
+ * Its height comes from the room the lockup has rather than from the slot,
43
+ * which is the whole content area tall: `row` gives every item the full height
44
+ * so that each can sit where it likes within it.
45
+ */
46
+ export declare function markElement(logo: ImageAsset | undefined, slot: Rect | undefined): string;
47
+ //# sourceMappingURL=lockup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockup.d.ts","sourceRoot":"","sources":["../../../src/templates/cover/lockup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAQ9D,sEAAsE;AACtE,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,QAAQ,EAAE,EAC1B,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,CAaR;AAED,yEAAyE;AACzE,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,UAAU,GAAG,SAAS,EAC5B,aAAa,EAAE,MAAM,GACpB,IAAI,CASN;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAUxE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,GAAG,SAAS,EAC5B,IAAI,EAAE,IAAI,GAAG,SAAS,GACrB,MAAM,CAiBR"}
@@ -0,0 +1,71 @@
1
+ import { image, row } from "../../layout/index.js";
2
+ /** The mark's height, as a fraction of the room the lockup has. */
3
+ const markScale = 0.72;
4
+ /** The clear space between the mark and the words, of the same room. */
5
+ const markGapScale = 0.24;
6
+ /** The widest of a block of lines, which is how wide the block is. */
7
+ export function linesWidth(lines, measure, fontFamily) {
8
+ return lines.reduce((widest, line) => Math.max(widest, measure(line.text, {
9
+ fontFamily,
10
+ fontSize: line.fontSize,
11
+ fontWeight: line.fontWeight,
12
+ })), 0);
13
+ }
14
+ /**
15
+ * How much of the row the mark claims, or nothing at all where the project has
16
+ * no logo, which is what takes the gap with it.
17
+ *
18
+ * The width and the gap come back together because the words need both before
19
+ * they can be fitted, and deriving either of them twice is how the room
20
+ * reserved stops matching the room used.
21
+ */
22
+ export function markSpace(logo, contentHeight) {
23
+ if (logo === undefined) {
24
+ return { width: 0, gap: 0 };
25
+ }
26
+ return {
27
+ width: Math.round(Math.round(contentHeight * markScale) * logo.aspect),
28
+ gap: Math.round(contentHeight * markGapScale),
29
+ };
30
+ }
31
+ /**
32
+ * Set the mark beside the words and centre the pair.
33
+ *
34
+ * A cover is a strip between about 2.6:1 and 6:1, so the mark goes next to the
35
+ * name rather than above it as the `wordmark` template has it: stacked, three
36
+ * elements in 400px of height leave nothing legible. The words are then set
37
+ * from the left of the slot they were given rather than centred within it, so
38
+ * that a wrapped name lines up under itself and the whole lockup still sits in
39
+ * the middle.
40
+ *
41
+ * A project with no logo takes the same path with a mark of no width, which is
42
+ * one arrangement rather than two: `row` centres a single item exactly as it
43
+ * centres a pair.
44
+ */
45
+ export function lockup(area, mark, textWidth) {
46
+ const [markSlot, textSlot] = row([{ size: mark.width }, { size: textWidth, gapBefore: mark.gap }], area);
47
+ return {
48
+ mark: mark.width === 0 ? undefined : markSlot,
49
+ text: textSlot ?? area,
50
+ };
51
+ }
52
+ /**
53
+ * The mark, centred down the slot it was given.
54
+ *
55
+ * Its height comes from the room the lockup has rather than from the slot,
56
+ * which is the whole content area tall: `row` gives every item the full height
57
+ * so that each can sit where it likes within it.
58
+ */
59
+ export function markElement(logo, slot) {
60
+ if (logo === undefined || slot === undefined) {
61
+ return "";
62
+ }
63
+ const height = Math.round(slot.height * markScale);
64
+ return image({
65
+ x: slot.x,
66
+ y: Math.round(slot.y + (slot.height - height) / 2),
67
+ width: slot.width,
68
+ height,
69
+ }, logo.href, { fit: "contain" });
70
+ }
71
+ //# sourceMappingURL=lockup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockup.js","sourceRoot":"","sources":["../../../src/templates/cover/lockup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAGnD,mEAAmE;AACnE,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB,wEAAwE;AACxE,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,sEAAsE;AACtE,MAAM,UAAU,UAAU,CACxB,KAA0B,EAC1B,OAAoB,EACpB,UAAkB;IAElB,OAAO,KAAK,CAAC,MAAM,CACjB,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CACf,IAAI,CAAC,GAAG,CACN,MAAM,EACN,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;QACjB,UAAU;QACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CACH,EACH,CAAC,CACF,CAAC;AACJ,CAAC;AAQD;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACvB,IAA4B,EAC5B,aAAqB;IAErB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACtE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,YAAY,CAAC;KAC9C,CAAC;AACJ,CAAC;AAQD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,MAAM,CAAC,IAAU,EAAE,IAAU,EAAE,SAAiB;IAC9D,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,GAAG,CAC9B,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAChE,IAAI,CACL,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;QAC7C,IAAI,EAAE,QAAQ,IAAI,IAAI;KACvB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAA4B,EAC5B,IAAsB;IAEtB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEnD,OAAO,KAAK,CACV;QACE,CAAC,EAAE,IAAI,CAAC,CAAC;QACT,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAClD,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM;KACP,EACD,IAAI,CAAC,IAAI,EACT,EAAE,GAAG,EAAE,SAAS,EAAE,CACnB,CAAC;AACJ,CAAC"}
@@ -17,11 +17,11 @@ import { docsLines } from "./lines.js";
17
17
  export const docsTemplate = {
18
18
  name: "docs",
19
19
  render({ props, config, dimensions, measure, logo, avatar, }) {
20
- const { width, height } = dimensions;
20
+ const { height } = dimensions;
21
21
  const { fontFamily, colors } = config;
22
22
  const frame = imageFrame(dimensions, config, avatar);
23
23
  const { pad } = frame;
24
- const mark = logoRect(logo, dimensions, pad, "start");
24
+ const mark = logoRect(logo, frame.full, pad, "start");
25
25
  const chrome = docsChrome(props, config, dimensions, pad, markRoom(mark?.width, pad / 2), measure);
26
26
  // The title starts below whichever of the trail and the logo reaches
27
27
  // furthest down. Both are measured from the top of the image, so the room
@@ -41,7 +41,7 @@ export const docsTemplate = {
41
41
  return (chrome.svg +
42
42
  logoElement(logo, mark) +
43
43
  body +
44
- footerLine(config, frame, width, avatar, measure));
44
+ footerLine(config, frame, avatar, measure));
45
45
  },
46
46
  };
47
47
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;;GASG;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,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,UAAU,CACvB,KAAK,EACL,MAAM,EACN,UAAU,EACV,GAAG,EACH,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,EAC9B,OAAO,CACR,CAAC;QAEF,qEAAqE;QACrE,0EAA0E;QAC1E,0EAA0E;QAC1E,gBAAgB;QAChB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;QAEjE,MAAM,IAAI,GAAG,SAAS,CACpB,SAAS,CAAC,KAAK,EAAE;YACf,OAAO;YACP,UAAU;YACV,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACnC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACrC,MAAM;SACP,CAAC,EACF,IAAI,EACJ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,CAC1D,CAAC;QAEF,OAAO,CACL,MAAM,CAAC,GAAG;YACV,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC;YACvB,IAAI;YACJ,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAClD,CAAC;IACJ,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;;GASG;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,MAAM,EAAE,GAAG,UAAU,CAAC;QAC9B,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,UAAU,CACvB,KAAK,EACL,MAAM,EACN,UAAU,EACV,GAAG,EACH,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,EAC9B,OAAO,CACR,CAAC;QAEF,qEAAqE;QACrE,0EAA0E;QAC1E,0EAA0E;QAC1E,gBAAgB;QAChB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;QAEjE,MAAM,IAAI,GAAG,SAAS,CACpB,SAAS,CAAC,KAAK,EAAE;YACf,OAAO;YACP,UAAU;YACV,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACnC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACrC,MAAM;SACP,CAAC,EACF,IAAI,EACJ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,CAC1D,CAAC;QAEF,OAAO,CACL,MAAM,CAAC,GAAG;YACV,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC;YACvB,IAAI;YACJ,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAC3C,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -18,13 +18,13 @@ const lineHeight = 1.24;
18
18
  export const eventTemplate = {
19
19
  name: "event",
20
20
  render({ props, config, dimensions, measure, logo, avatar, }) {
21
- const { width, height } = dimensions;
21
+ const { height } = dimensions;
22
22
  const { fontFamily, colors } = config;
23
23
  const frame = imageFrame(dimensions, config, avatar, {
24
24
  padScale: 0.09,
25
25
  });
26
26
  const { pad } = frame;
27
- const mark = logoRect(logo, dimensions, pad, "middle");
27
+ const mark = logoRect(logo, frame.full, pad, "middle");
28
28
  const area = contentArea(frame, markRoom(mark?.height, pad / 2));
29
29
  const lines = eventLines(props, {
30
30
  measure,
@@ -49,7 +49,7 @@ export const eventTemplate = {
49
49
  lineHeight,
50
50
  anchor: "middle",
51
51
  });
52
- const footer = footerLine(config, frame, width, avatar, measure, "middle");
52
+ const footer = footerLine(config, frame, avatar, measure, "middle");
53
53
  return (logoElement(logo, mark) +
54
54
  datePlate(date, dateSlot, plateStyle(config), measure) +
55
55
  body +
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/event/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE3E,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhE,2DAA2D;AAC3D,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAa;IACrC,IAAI,EAAE,OAAO;IACb,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,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE;YACnD,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAEjE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE;YAC9B,OAAO;YACP,UAAU;YACV,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACnC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACtC,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAExC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,KAAK,CAChC;YACE,EAAE,IAAI,EAAE,KAAK,EAAE;YACf;gBACE,IAAI,EAAE,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC;gBACpC,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;aACvD;SACF,EACD,IAAI,CACL,CAAC;QAEF,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE;YACrC,UAAU;YACV,IAAI,EAAE,MAAM,CAAC,UAAU;YACvB,UAAU;YACV,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAE3E,OAAO,CACL,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC;YACvB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;YACtD,IAAI;YACJ,MAAM,CACP,CAAC;IACJ,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/event/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE3E,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhE,2DAA2D;AAC3D,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAa;IACrC,IAAI,EAAE,OAAO;IACb,MAAM,CAAC,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,IAAI,EACJ,MAAM,GACU;QAChB,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;QAC9B,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE;YACnD,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAEjE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE;YAC9B,OAAO;YACP,UAAU;YACV,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACnC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACtC,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAExC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,KAAK,CAChC;YACE,EAAE,IAAI,EAAE,KAAK,EAAE;YACf;gBACE,IAAI,EAAE,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC;gBACpC,SAAS,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;aACvD;SACF,EACD,IAAI,CACL,CAAC;QAEF,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE;YACrC,UAAU;YACV,IAAI,EAAE,MAAM,CAAC,UAAU;YACvB,UAAU;YACV,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEpE,OAAO,CACL,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC;YACvB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;YACtD,IAAI;YACJ,MAAM,CACP,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -5,6 +5,9 @@ import type { Dimensions, ResolvedConfig } from "../types.js";
5
5
  * Every template asks for it here rather than working it out, which is what
6
6
  * stops the twelve of them drifting apart. It is one number for the footer,
7
7
  * the byline and the attribution alike, since they are all the same line.
8
+ *
9
+ * The dimensions are the frame's rather than the image's, so a size with a
10
+ * safe area gets a footer scaled to the part of the picture that is seen.
8
11
  */
9
12
  export declare function footerFontSize(dimensions: Dimensions): number;
10
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../src/templates/footer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAkB9D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAO7D;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAEzD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,eAAe,GACzB,MAAM,CAeR"}
1
+ {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../src/templates/footer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA+B9D;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAU7D;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;CAC9C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAEzD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,eAAe,GACzB,MAAM,CAeR"}
@@ -13,15 +13,30 @@ const footerScale = 0.036;
13
13
  * and keeps the proportions it had.
14
14
  */
15
15
  const footerWidthFloor = 0.026;
16
+ /**
17
+ * The most it may be, as a fraction of the height, which is about a twelfth.
18
+ *
19
+ * The width floor assumes an image whose proportions are somewhere near a
20
+ * share card's, and a profile cover is not: a LinkedIn Page cover is 6:1, so
21
+ * the floor asks for 72px of footer in a band that has 250px for the title,
22
+ * and the site's URL comes out the same size as its name. The ceiling is what
23
+ * says the line along the bottom is a footer rather than a second heading. It
24
+ * is above every share preset, so nothing that was drawn before this existed
25
+ * is drawn differently.
26
+ */
27
+ const footerHeightCeiling = 0.08;
16
28
  /**
17
29
  * The size the line along the bottom is drawn at.
18
30
  *
19
31
  * Every template asks for it here rather than working it out, which is what
20
32
  * stops the twelve of them drifting apart. It is one number for the footer,
21
33
  * the byline and the attribution alike, since they are all the same line.
34
+ *
35
+ * The dimensions are the frame's rather than the image's, so a size with a
36
+ * safe area gets a footer scaled to the part of the picture that is seen.
22
37
  */
23
38
  export function footerFontSize(dimensions) {
24
- return Math.round(Math.max(dimensions.height * footerScale, dimensions.width * footerWidthFloor));
39
+ return Math.round(Math.min(Math.max(dimensions.height * footerScale, dimensions.width * footerWidthFloor), dimensions.height * footerHeightCeiling));
25
40
  }
26
41
  /**
27
42
  * The baseline of a footer sitting on the bottom margin.
@@ -1 +1 @@
1
- {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../src/templates/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAG9D,8DAA8D;AAC9D,MAAM,WAAW,GAAG,KAAK,CAAC;AAE1B;;;;;;;;;;GAUG;AACH,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,UAAsB;IACnD,OAAO,IAAI,CAAC,KAAK,CACf,IAAI,CAAC,GAAG,CACN,UAAU,CAAC,MAAM,GAAG,WAAW,EAC/B,UAAU,CAAC,KAAK,GAAG,gBAAgB,CACpC,CACF,CAAC;AACJ,CAAC;AAeD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,GAAW,EACX,QAAgB;IAEhB,OAAO,WAAW,CAAC,MAAM,GAAG,GAAG,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,SAAS,CAAC,MAAsB;IAC9C,OAAO,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAsB,EACtB,SAA0B;IAE1B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE;QACtC,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;QAC9B,WAAW,EAAE,SAAS,CAAC,OAAO;QAC9B,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;KACpE,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../src/templates/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAG9D,8DAA8D;AAC9D,MAAM,WAAW,GAAG,KAAK,CAAC;AAE1B;;;;;;;;;;GAUG;AACH,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;;;;;;;;;GAUG;AACH,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,UAAsB;IACnD,OAAO,IAAI,CAAC,KAAK,CACf,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,GAAG,CACN,UAAU,CAAC,MAAM,GAAG,WAAW,EAC/B,UAAU,CAAC,KAAK,GAAG,gBAAgB,CACpC,EACD,UAAU,CAAC,MAAM,GAAG,mBAAmB,CACxC,CACF,CAAC;AACJ,CAAC;AAeD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,GAAW,EACX,QAAgB;IAEhB,OAAO,WAAW,CAAC,MAAM,GAAG,GAAG,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,SAAS,CAAC,MAAsB;IAC9C,OAAO,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAsB,EACtB,SAA0B;IAE1B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE;QACtC,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;QAC9B,WAAW,EAAE,SAAS,CAAC,OAAO;QAC9B,GAAG,CAAC,SAAS,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;KACpE,CAAC,CAAC;AACL,CAAC"}
@@ -13,7 +13,10 @@ export interface Frame {
13
13
  /** The margin, applied to every edge. */
14
14
  readonly pad: number;
15
15
  readonly footerFontSize: number;
16
- /** The whole image, as the rectangle the content is inset from. */
16
+ /**
17
+ * The rectangle the content is inset from: the whole image, or the part of
18
+ * it that survives being displayed where the config named a safe area.
19
+ */
17
20
  readonly full: Rect;
18
21
  /**
19
22
  * Vertical room to leave below the content, which is the footer line plus
@@ -25,8 +28,19 @@ export interface Frame {
25
28
  }
26
29
  /** What a template can tell the frame about itself. */
27
30
  export interface FrameOptions {
28
- /** The margin, as a fraction of the image's width. */
31
+ /** The margin, as a fraction of the frame's width. */
29
32
  readonly padScale?: number;
33
+ /**
34
+ * The margin outright, for a template whose frame is too wide for its height
35
+ * to take one from the width.
36
+ *
37
+ * A fraction of the width is the right unit for an image with the
38
+ * proportions of a card, and the wrong one for a strip: on a 6:1 cover the
39
+ * usual 7.5% of the width is a third of the height, spent on margins above
40
+ * and below the only band there is. Wins over `padScale` where both are
41
+ * given.
42
+ */
43
+ readonly pad?: number;
30
44
  /**
31
45
  * Whether the template draws something of its own on the bottom line, such
32
46
  * as a byline, so the room is left for it even where the config has no
@@ -38,6 +52,16 @@ export interface FrameOptions {
38
52
  * Work out a template's frame. The avatar counts as a footer even where the
39
53
  * config carries no text, since the picture is drawn on the same line and
40
54
  * needs the same room.
55
+ *
56
+ * The safe area is worked out first and everything else is measured against
57
+ * it, rather than against the image. That matters most for the margin: a
58
+ * YouTube banner is 2560 across and the part of it anyone sees is 1546, so a
59
+ * margin taken from the image would spend a quarter of the visible width on
60
+ * clear space. It matters for the footer too, which would otherwise sit on the
61
+ * bottom edge of a picture that is cropped before it gets there.
62
+ *
63
+ * A config naming no safe area gets the whole image back, so every one of
64
+ * these is the arithmetic it always was.
41
65
  */
42
66
  export declare function imageFrame(dimensions: Dimensions, config: ResolvedConfig, avatar: ImageAsset | undefined, options?: FrameOptions): Frame;
43
67
  /**
@@ -49,7 +73,7 @@ export declare function imageFrame(dimensions: Dimensions, config: ResolvedConfi
49
73
  */
50
74
  export declare function markRoom(height: number | undefined, gap: number): number;
51
75
  /**
52
- * The space a template's content has: the whole image, less the margins, less
76
+ * The space a template's content has: the frame, less the margins, less
53
77
  * whatever sits along the top, less the footer line.
54
78
  *
55
79
  * `top` is what {@link markRoom} worked out, or whatever else the template put
@@ -1 +1 @@
1
- {"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/templates/frame.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ1E;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAK;IACpB,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,OAAO,GAAE,YAAiB,GACzB,KAAK,CAcP;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,SAAI,GAAG,IAAI,CAOvD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1D"}
1
+ {"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/templates/frame.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQ1E;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAK;IACpB,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,OAAO,GAAE,YAAiB,GACzB,KAAK,CAgBP;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,SAAI,GAAG,IAAI,CAOvD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1D"}
@@ -1,4 +1,5 @@
1
1
  import { footerBaseline, footerFontSize, hasFooter } from "./footer.js";
2
+ import { safeRect } from "../config/safe-area.js";
2
3
  import { inset } from "../layout/index.js";
3
4
  /** Margin from the image edge, as a fraction of its width. */
4
5
  const defaultPadScale = 0.075;
@@ -8,18 +9,29 @@ const footerGap = 0.02;
8
9
  * Work out a template's frame. The avatar counts as a footer even where the
9
10
  * config carries no text, since the picture is drawn on the same line and
10
11
  * needs the same room.
12
+ *
13
+ * The safe area is worked out first and everything else is measured against
14
+ * it, rather than against the image. That matters most for the margin: a
15
+ * YouTube banner is 2560 across and the part of it anyone sees is 1546, so a
16
+ * margin taken from the image would spend a quarter of the visible width on
17
+ * clear space. It matters for the footer too, which would otherwise sit on the
18
+ * bottom edge of a picture that is cropped before it gets there.
19
+ *
20
+ * A config naming no safe area gets the whole image back, so every one of
21
+ * these is the arithmetic it always was.
11
22
  */
12
23
  export function imageFrame(dimensions, config, avatar, options = {}) {
13
- const { width, height } = dimensions;
14
- const pad = Math.round(width * (options.padScale ?? defaultPadScale));
15
- const fontSize = footerFontSize(dimensions);
24
+ const full = safeRect(dimensions, config.safeArea);
25
+ const pad = options.pad ??
26
+ Math.round(full.width * (options.padScale ?? defaultPadScale));
27
+ const fontSize = footerFontSize(full);
16
28
  const isDrawn = options.footer === true || hasFooter(config) || avatar !== undefined;
17
29
  return {
18
30
  pad,
19
31
  footerFontSize: fontSize,
20
- full: { x: 0, y: 0, width, height },
21
- footerRoom: isDrawn ? fontSize + Math.round(height * footerGap) : 0,
22
- footerY: footerBaseline(height, pad, fontSize),
32
+ full,
33
+ footerRoom: isDrawn ? fontSize + Math.round(full.height * footerGap) : 0,
34
+ footerY: footerBaseline(full.y + full.height, pad, fontSize),
23
35
  };
24
36
  }
25
37
  /**
@@ -33,7 +45,7 @@ export function markRoom(height, gap) {
33
45
  return height === undefined || height === 0 ? 0 : height + gap;
34
46
  }
35
47
  /**
36
- * The space a template's content has: the whole image, less the margins, less
48
+ * The space a template's content has: the frame, less the margins, less
37
49
  * whatever sits along the top, less the footer line.
38
50
  *
39
51
  * `top` is what {@link markRoom} worked out, or whatever else the template put
@@ -1 +1 @@
1
- {"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/templates/frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAI3C,8DAA8D;AAC9D,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,gFAAgF;AAChF,MAAM,SAAS,GAAG,IAAI,CAAC;AAsCvB;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,UAAsB,EACtB,MAAsB,EACtB,MAA8B,EAC9B,OAAO,GAAiB,EAAE;IAE1B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,eAAe,CAAC,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,OAAO,GACX,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,SAAS,CAAC;IAEvE,OAAO;QACL,GAAG;QACH,cAAc,EAAE,QAAQ;QACxB,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE;QACnC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,MAA0B,EAAE,GAAW;IAC9D,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC;AACjE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,KAAY,EAAE,GAAG,GAAG,CAAC;IAC/C,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;QACvB,GAAG,EAAE,KAAK,CAAC,GAAG,GAAG,GAAG;QACpB,KAAK,EAAE,KAAK,CAAC,GAAG;QAChB,IAAI,EAAE,KAAK,CAAC,GAAG;QACf,MAAM,EAAE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,UAAU;KACrC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAW;IAChD,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/templates/frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAI3C,8DAA8D;AAC9D,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,gFAAgF;AAChF,MAAM,SAAS,GAAG,IAAI,CAAC;AAoDvB;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CACxB,UAAsB,EACtB,MAAsB,EACtB,MAA8B,EAC9B,OAAO,GAAiB,EAAE;IAE1B,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,MAAM,GAAG,GACP,OAAO,CAAC,GAAG;QACX,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,eAAe,CAAC,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,OAAO,GACX,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,SAAS,CAAC;IAEvE,OAAO;QACL,GAAG;QACH,cAAc,EAAE,QAAQ;QACxB,IAAI;QACJ,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,MAA0B,EAAE,GAAW;IAC9D,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC;AACjE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,KAAY,EAAE,GAAG,GAAG,CAAC;IAC/C,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;QACvB,GAAG,EAAE,KAAK,CAAC,GAAG,GAAG,GAAG;QACpB,KAAK,EAAE,KAAK,CAAC,GAAG;QAChB,IAAI,EAAE,KAAK,CAAC,GAAG;QACf,MAAM,EAAE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,UAAU;KACrC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAW;IAChD,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9B,CAAC"}
@@ -8,6 +8,7 @@ export { articleTemplate } from "./article/index.js";
8
8
  export { bannerTemplate } from "./banner/index.js";
9
9
  export { cardTemplate } from "./card/index.js";
10
10
  export { codeTemplate } from "./code/index.js";
11
+ export { coverTemplate } from "./cover/index.js";
11
12
  export { docsTemplate } from "./docs/index.js";
12
13
  export { eventTemplate } from "./event/index.js";
13
14
  export { photoTemplate } from "./photo/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAe5C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAc/D,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgB5C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAe/D,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}