@certrev/cert-block 1.1.1 → 1.2.0-canary.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 (61) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +50 -4
  3. package/dist/builder/cert-chrome-data.d.ts +10 -0
  4. package/dist/builder/cert-chrome-data.d.ts.map +1 -1
  5. package/dist/builder/cert-chrome-data.js.map +1 -1
  6. package/dist/builder/cert-review-card.d.ts.map +1 -1
  7. package/dist/builder/cert-review-card.js +22 -2
  8. package/dist/builder/cert-review-card.js.map +1 -1
  9. package/dist/builder/envelope-face.d.ts +25 -1
  10. package/dist/builder/envelope-face.d.ts.map +1 -1
  11. package/dist/builder/envelope-face.js +40 -0
  12. package/dist/builder/envelope-face.js.map +1 -1
  13. package/dist/builder/index.d.ts +1 -1
  14. package/dist/builder/index.d.ts.map +1 -1
  15. package/dist/builder/index.js +1 -1
  16. package/dist/builder/index.js.map +1 -1
  17. package/dist/reader/face.d.ts +12 -0
  18. package/dist/reader/face.d.ts.map +1 -0
  19. package/dist/reader/face.js +19 -0
  20. package/dist/reader/face.js.map +1 -0
  21. package/dist/reader/helpers.d.ts +48 -0
  22. package/dist/reader/helpers.d.ts.map +1 -0
  23. package/dist/reader/helpers.js +166 -0
  24. package/dist/reader/helpers.js.map +1 -0
  25. package/dist/reader/index.d.ts +10 -0
  26. package/dist/reader/index.d.ts.map +1 -0
  27. package/dist/reader/index.js +10 -0
  28. package/dist/reader/index.js.map +1 -0
  29. package/dist/reader/logo.d.ts +4 -0
  30. package/dist/reader/logo.d.ts.map +1 -0
  31. package/dist/reader/logo.js +23 -0
  32. package/dist/reader/logo.js.map +1 -0
  33. package/dist/reader/reader-css.generated.d.ts +2 -0
  34. package/dist/reader/reader-css.generated.d.ts.map +1 -0
  35. package/dist/reader/reader-css.generated.js +6 -0
  36. package/dist/reader/reader-css.generated.js.map +1 -0
  37. package/dist/reader/render.d.ts +26 -0
  38. package/dist/reader/render.d.ts.map +1 -0
  39. package/dist/reader/render.js +230 -0
  40. package/dist/reader/render.js.map +1 -0
  41. package/dist/reader/tokens.d.ts +8 -0
  42. package/dist/reader/tokens.d.ts.map +1 -0
  43. package/dist/reader/tokens.js +65 -0
  44. package/dist/reader/tokens.js.map +1 -0
  45. package/dist/verify/get-verified-delivery.d.ts.map +1 -1
  46. package/dist/verify/get-verified-delivery.js +5 -1
  47. package/dist/verify/get-verified-delivery.js.map +1 -1
  48. package/package.json +7 -1
  49. package/src/builder/cert-chrome-data.ts +10 -0
  50. package/src/builder/cert-review-card.tsx +31 -2
  51. package/src/builder/envelope-face.ts +54 -5
  52. package/src/builder/index.tsx +3 -0
  53. package/src/reader/face.ts +35 -0
  54. package/src/reader/helpers.ts +178 -0
  55. package/src/reader/index.ts +14 -0
  56. package/src/reader/logo.ts +28 -0
  57. package/src/reader/reader-css.generated.ts +5 -0
  58. package/src/reader/reader.css +550 -0
  59. package/src/reader/render.ts +319 -0
  60. package/src/reader/tokens.ts +76 -0
  61. package/src/verify/get-verified-delivery.ts +5 -1
@@ -0,0 +1,8 @@
1
+ export interface ReaderTokens {
2
+ /** The value of the section's `style` attribute. */
3
+ readonly style: string;
4
+ /** The ink on the accent: `#ffffff` or `#141414`. The logo is white on the first and mono on the second. */
5
+ readonly fg: string;
6
+ }
7
+ export declare function readerTokens(def: unknown): ReaderTokens;
8
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/reader/tokens.ts"],"names":[],"mappings":"AAgDA,MAAM,WAAW,YAAY;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,4GAA4G;IAC5G,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAoBvD"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * `certrev-reader-tokens`: the four CSS custom properties a reader section carries on its root, from the render def.
3
+ *
4
+ * --cr-ba the accent the card cap and pill paint: the def's `barInk`, else its `accentColor`, else navy
5
+ * --cr-ba-fg the ink on that accent: white, or `#141414` when the def baked it for the colour that painted
6
+ * --cr-br the corner radius
7
+ * --cr-bf the font stack for the brand's `fontSlot`
8
+ *
9
+ * The values land inside a double-quoted `style` attribute, so a colour or radius that could break out of it
10
+ * (`; ( ) { } < > "` or a space) is dropped to its default rather than escaped into something half valid. The variable
11
+ * names are the reader stylesheet's (`reader.css`), which `.certrev-reader` declares defaults for.
12
+ */
13
+ import { asText } from '../components/escape.js';
14
+ import { esc, rec, textOr } from './helpers.js';
15
+ /** The accent when the def has none: CertREV navy. */
16
+ const DEFAULT_ACCENT = '#0A1B3F';
17
+ const DEFAULT_RADIUS = '14px';
18
+ /** The foreground the def bakes for a light accent; anything else is the white default. */
19
+ const DARK_INK = '#141414';
20
+ /**
21
+ * The font stack per `fontSlot`, in one table so the Liquid `certrev-reader-tokens` snippet and this one are compared
22
+ * on a single list. An unknown or missing slot is the sans stack, as in the snippet. The serif and grotesk stacks name
23
+ * the reader's own `@font-face` aliases first ("CertREV Reader Serif" / "CertREV Reader Grotesk", declared in
24
+ * `reader.css`), then the legacy family and the generic fallbacks, as the snippet's `--cr-bf` does.
25
+ */
26
+ function fontStack(slot) {
27
+ switch (slot) {
28
+ case 'serif':
29
+ return "'CertREV Reader Serif', 'Playfair Display', ui-serif, Georgia, serif";
30
+ case 'grotesk':
31
+ return "'CertREV Reader Grotesk', 'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif";
32
+ case 'mono':
33
+ return "'JetBrains Mono', ui-monospace, monospace";
34
+ case 'system':
35
+ return "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
36
+ default:
37
+ return "'DM Sans', ui-sans-serif, system-ui, sans-serif";
38
+ }
39
+ }
40
+ /** A token value that cannot leave the style attribute, or '' (which the caller defaults). */
41
+ function guarded(value) {
42
+ const text = textOr(value);
43
+ return /[;(){}<>" ]/.test(text) ? '' : text;
44
+ }
45
+ export function readerTokens(def) {
46
+ const rd = rec(def);
47
+ const tokens = rec(rd.tokens);
48
+ const barInk = guarded(tokens.barInk);
49
+ const accent = guarded(tokens.accentColor);
50
+ const ba = barInk || accent || DEFAULT_ACCENT;
51
+ // The ink follows the value that painted the accent: a def with a bar ink takes the foreground baked for it
52
+ // (barInkFg); one that paints its accent colour takes the one baked for that colour (accentFg).
53
+ let fg = '#ffffff';
54
+ if (barInk !== '') {
55
+ if (rd.barInkFg === DARK_INK)
56
+ fg = DARK_INK;
57
+ }
58
+ else if (accent !== '' && rd.accentFg === DARK_INK) {
59
+ fg = DARK_INK;
60
+ }
61
+ const br = guarded(tokens.cornerRadius) || DEFAULT_RADIUS;
62
+ const bf = fontStack(asText(tokens.fontSlot));
63
+ return { style: `--cr-ba:${esc(ba)};--cr-ba-fg:${fg};--cr-br:${esc(br)};--cr-bf:${bf}`, fg };
64
+ }
65
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/reader/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE/C,sDAAsD;AACtD,MAAM,cAAc,GAAG,SAAS,CAAA;AAChC,MAAM,cAAc,GAAG,MAAM,CAAA;AAC7B,2FAA2F;AAC3F,MAAM,QAAQ,GAAG,SAAS,CAAA;AAE1B;;;;;GAKG;AACH,SAAS,SAAS,CAAC,IAAY;IAC9B,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,OAAO;YACX,OAAO,sEAAsE,CAAA;QAC9E,KAAK,SAAS;YACb,OAAO,qFAAqF,CAAA;QAC7F,KAAK,MAAM;YACV,OAAO,2CAA2C,CAAA;QACnD,KAAK,QAAQ;YACZ,OAAO,8EAA8E,CAAA;QACtF;YACC,OAAO,iDAAiD,CAAA;IAC1D,CAAC;AACF,CAAC;AAED,8FAA8F;AAC9F,SAAS,OAAO,CAAC,KAAc;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1B,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAC5C,CAAC;AASD,MAAM,UAAU,YAAY,CAAC,GAAY;IACxC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;IACnB,MAAM,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;IAE7B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IAC1C,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,IAAI,cAAc,CAAA;IAE7C,4GAA4G;IAC5G,gGAAgG;IAChG,IAAI,EAAE,GAAG,SAAS,CAAA;IAClB,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QACnB,IAAI,EAAE,CAAC,QAAQ,KAAK,QAAQ;YAAE,EAAE,GAAG,QAAQ,CAAA;IAC5C,CAAC;SAAM,IAAI,MAAM,KAAK,EAAE,IAAI,EAAE,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtD,EAAE,GAAG,QAAQ,CAAA;IACd,CAAC;IAED,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,cAAc,CAAA;IACzD,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC7C,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,YAAY,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;AAC7F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-verified-delivery.d.ts","sourceRoot":"","sources":["../../src/verify/get-verified-delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,OAAO,KAAK,EAEX,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,qGAAqG;AACrG,MAAM,MAAM,cAAc,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAAE,GAC5G;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAEvE,mGAAmG;AACnG,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAC9C;AAED,MAAM,WAAW,0BAA0B;IAC1C,mGAAmG;IACnG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAA;IAC1C,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAA;IACzC,mGAAmG;IACnG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,kFAAkF;AAClF,QAAA,MAAM,mBAAmB,0BAAwE,CAAA;AAMjG,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED,wGAAwG;AACxG,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC,GACvF,MAAM,CAER;AAKD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA4BzE;AAyCD,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,GAAG,gBAAgB,CAI/F;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASrG;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC,GACjG,gBAAgB,GAAG,SAAS,CAG9B;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC,EACzF,KAAK,GAAE,QAAQ,CAAC,cAAc,CAAuB,GACnD,IAAI,CAEN;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
1
+ {"version":3,"file":"get-verified-delivery.d.ts","sourceRoot":"","sources":["../../src/verify/get-verified-delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACzE,OAAO,KAAK,EAEX,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,qGAAqG;AACrG,MAAM,MAAM,cAAc,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAAE,GAC5G;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAEvE,mGAAmG;AACnG,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAA;CAC9C;AAED,MAAM,WAAW,0BAA0B;IAC1C,mGAAmG;IACnG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAA;IAC1C,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAA;IACzC,mGAAmG;IACnG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,kFAAkF;AAClF,QAAA,MAAM,mBAAmB,0BAAwE,CAAA;AAMjG,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED,wGAAwG;AACxG,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC,GACvF,MAAM,CAER;AAKD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAgCzE;AAyCD,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,GAAG,gBAAgB,CAI/F;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASrG;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC,GACjG,gBAAgB,GAAG,SAAS,CAG9B;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC,EACzF,KAAK,GAAE,QAAQ,CAAC,cAAc,CAAuB,GACnD,IAAI,CAEN;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAA"}
@@ -52,7 +52,7 @@ const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v)
52
52
  export function parseRenderDef(value) {
53
53
  if (!isRecord(value))
54
54
  return null;
55
- const { v, preset, rung, tokens, hidden, barInkFg, layout, customFace } = value;
55
+ const { v, preset, rung, tokens, hidden, barInkFg, accentFg, face: faceName, layout, customFace } = value;
56
56
  if (typeof v !== 'number' || !Number.isFinite(v))
57
57
  return null;
58
58
  if (!isString(preset) || !isString(rung) || !isRecord(tokens))
@@ -79,6 +79,10 @@ export function parseRenderDef(value) {
79
79
  rung,
80
80
  tokens: tokenOut,
81
81
  ...(barInkFg === '#141414' || barInkFg === '#ffffff' ? { barInkFg } : {}),
82
+ // 1.2.0: the reader face's two keys. 1.1.x dropped both; they are kept only when well-formed, so a def that
83
+ // carries neither parses to exactly the object 1.1.1 returned for it.
84
+ ...(accentFg === '#141414' || accentFg === '#ffffff' ? { accentFg } : {}),
85
+ ...(isString(faceName) ? { face: faceName } : {}),
82
86
  hidden: [...hidden],
83
87
  ...(layout !== undefined ? { layout } : {}),
84
88
  ...(face ? { customFace: face } : {}),
@@ -1 +1 @@
1
- {"version":3,"file":"get-verified-delivery.js","sourceRoot":"","sources":["../../src/verify/get-verified-delivery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get-verified-delivery.js","sourceRoot":"","sources":["../../src/verify/get-verified-delivery.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@certrev/cert-block",
3
- "version": "1.1.1",
3
+ "version": "1.2.0-canary.0",
4
4
  "description": "Headless render edge for the CertREV CertDeliveryEnvelope: SSR-safe React cert components, a framework-agnostic <certrev-badge> Web Component, a schema.org JSON-LD projector, and a fail-closed verify layer over the shared VerdictKernel.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,6 +27,11 @@
27
27
  "types": "./dist/builder/envelope-face.d.ts",
28
28
  "default": "./dist/builder/envelope-face.js"
29
29
  },
30
+ "./reader": {
31
+ "types": "./dist/reader/index.d.ts",
32
+ "default": "./dist/reader/index.js"
33
+ },
34
+ "./reader.css": "./src/reader/reader.css",
30
35
  "./webcomponent": {
31
36
  "types": "./dist/webcomponent/certrev-badge.d.ts",
32
37
  "default": "./dist/webcomponent/certrev-badge.js"
@@ -65,6 +70,7 @@
65
70
  "scripts": {
66
71
  "build": "tsc && pnpm build:modal-bundle",
67
72
  "build:modal-bundle": "pnpm dlx esbuild@0.27.7 src/modal/certrev-cert.entry.ts --bundle --minify --target=es2020 --format=iife --legal-comments=none --tsconfig-raw='{\"compilerOptions\":{\"target\":\"ES2017\",\"module\":\"esnext\",\"strict\":true}}' --banner:js='/* biome-ignore-all format: generated cert-badge bundle, see @certrev/cert-block src/modal/ */ /* biome-ignore-all lint: generated cert-badge bundle, see @certrev/cert-block src/modal/ */' --outfile=dist/modal/certrev-cert.js",
73
+ "refresh:reader": "node scripts/refresh-reader.mjs",
68
74
  "typecheck": "tsc --noEmit",
69
75
  "test": "vitest run"
70
76
  },
@@ -47,6 +47,16 @@ export interface CertChromeRenderDef {
47
47
  }
48
48
  /** The auto-contrast bar foreground — present only on a barInk-themed face (v2). */
49
49
  readonly barInkFg?: '#141414' | '#ffffff'
50
+ /**
51
+ * The ink painted over the ACCENT fill, as the portal derived it (1.2.0, reader face). Only the reader face reads
52
+ * it: the legacy face re-derives its own accent ink from `tokens.accentColor` and ignores this.
53
+ */
54
+ readonly accentFg?: '#141414' | '#ffffff'
55
+ /**
56
+ * The face the brand chose (1.2.0). `'reader'` selects the certrev.com reader face; absent, or any other value,
57
+ * paints the face 1.1.1 paints (unknown faces degrade to the legacy face, never to nothing).
58
+ */
59
+ readonly face?: string
50
60
  /** The subtractive field-visibility hide-set. */
51
61
  readonly hidden: readonly string[]
52
62
  /**
@@ -23,11 +23,12 @@ import { Suspense } from 'react'
23
23
  import { memoToggleFor, toggleMemo } from '../components/memo-toggle.js'
24
24
  import { type CertBlockMode, renderCertBlock } from '../components/render-cert-block.js'
25
25
  import { CERT_STRINGS_VERSION, type ResolvedBlockTheme } from '../components/render-def.js'
26
+ import { READER_CSS } from '../reader/reader-css.generated.js'
26
27
  import { getVerifiedDelivery, peekVerifiedDelivery, type VerifiedDelivery } from '../verify/get-verified-delivery.js'
27
28
  import type { BuilderCertChromeData } from './cert-chrome-data.js'
28
29
  import { BUILDER_CERT_CHROME_KEYS } from './cert-chrome-data.js'
29
30
  import { cardDeliveryRuntime } from './delivery-runtime.js'
30
- import { envelopeCardInput } from './envelope-face.js'
31
+ import { envelopeCardHtml, envelopeCardInput, isReaderFaceDef } from './envelope-face.js'
31
32
 
32
33
  /**
33
34
  * The canonical Builder block name. A brand's registration + the portal
@@ -147,8 +148,17 @@ function suspendOn(key: string, start: () => Promise<VerifiedDelivery>): Verifie
147
148
  * in; the button is native, so Enter and Space reach it as clicks. Bound after hydration only: the
148
149
  * server HTML is the collapsed face, which is also what a reader without JS keeps (the whole memo
149
150
  * is still in the text for a screen reader, and the desktop never clamps it).
151
+ *
152
+ * `reader` (1.2.0) is true ONLY for a def whose `face` is `'reader'`; it adds two things to the wrapper and nothing to
153
+ * any other face: `data-certrev-face="reader"` and `display: flow-root`. The reader sidebar card is a right float, and
154
+ * on a Shopify page the placement script and its wrapper contain it; a Builder block has no such ancestor, so the
155
+ * wrapper contains the float itself and the block keeps its own box in the page.
150
156
  */
151
- function EnvelopeFace(props: { readonly html: string; readonly defVersion: number | undefined }) {
157
+ function EnvelopeFace(props: {
158
+ readonly html: string
159
+ readonly defVersion: number | undefined
160
+ readonly reader?: boolean
161
+ }) {
152
162
  const ref = React.useRef<HTMLDivElement>(null)
153
163
  React.useEffect(() => {
154
164
  const el = ref.current
@@ -169,6 +179,7 @@ function EnvelopeFace(props: { readonly html: string; readonly defVersion: numbe
169
179
  data-certrev-delivery=""
170
180
  data-certrev-strings-version={CERT_STRINGS_VERSION}
171
181
  data-certrev-def-version={props.defVersion}
182
+ {...(props.reader ? { 'data-certrev-face': 'reader', style: { display: 'flow-root' } } : {})}
172
183
  // biome-ignore lint/security/noDangerouslySetInnerHtml: renderCertBlock is the escaping-safe SSR string renderer
173
184
  dangerouslySetInnerHTML={{ __html: props.html }}
174
185
  />
@@ -192,6 +203,24 @@ function EnvelopeCertReviewCard(props: {
192
203
  )
193
204
  // Revoked, expired, unverifiable, for another entry, or unreachable: nothing at all.
194
205
  if (settled.verdict.decision !== 'render') return null
206
+ // The reader face is opt-in by the def's own `face` and is chosen HERE and nowhere else on this path; every other
207
+ // def (no face, an unknown face) falls through to the legacy lines below, untouched since 1.1.1.
208
+ if (isReaderFaceDef(settled.renderDef)) {
209
+ const reader = envelopeCardHtml(settled.verdict.payload.content, settled.renderDef, {
210
+ mode: props.mode,
211
+ part: props.part,
212
+ certId: settled.verdict.payload.certId,
213
+ })
214
+ if (!reader) return null
215
+ return (
216
+ <EnvelopeFace
217
+ reader
218
+ // The stylesheet rides inside the face, once per card; it is the portal's reader CSS byte for byte.
219
+ html={`<style data-certrev-reader-css>${READER_CSS}</style>${reader}`}
220
+ defVersion={settled.renderDef ? settled.renderDef.v : undefined}
221
+ />
222
+ )
223
+ }
195
224
  const input = envelopeCardInput(settled.verdict.payload.content, settled.renderDef, {
196
225
  mode: props.mode,
197
226
  part: props.part,
@@ -26,14 +26,16 @@
26
26
  * it only returns null when the verified content cannot make a face (no reviewer, no verify URL).
27
27
  */
28
28
 
29
- import type {
30
- CertBlockFace,
31
- CertBlockLayout,
32
- CertBlockMode,
33
- RenderCertBlockInput,
29
+ import {
30
+ type CertBlockFace,
31
+ type CertBlockLayout,
32
+ type CertBlockMode,
33
+ type RenderCertBlockInput,
34
+ renderCertBlock,
34
35
  } from '../components/render-cert-block.js'
35
36
  import { accentFg, HIDEABLE_FIELDS, isOpaqueHexColor, type ResolvedBlockTheme } from '../components/render-def.js'
36
37
  import type { CertContent } from '../contract/kernel.js'
38
+ import { type ReaderLayout, renderReaderFace } from '../reader/render.js'
37
39
  import type { CertChromeRenderDef } from './cert-chrome-data.js'
38
40
 
39
41
  /**
@@ -74,6 +76,10 @@ export interface EnvelopeCardOptions {
74
76
  readonly mode?: unknown
75
77
  /** Banner memo placement, passed through as on the options path. */
76
78
  readonly part?: unknown
79
+ /** The verified payload's `certId`: stamped on the reader face (`data-certrev-cert-id`). The legacy face ignores it. */
80
+ readonly certId?: unknown
81
+ /** A CertREV preview, never a live page: the reader face words the cue's empty slot as the demo does. Only `true` counts. */
82
+ readonly illustrative?: unknown
77
83
  }
78
84
 
79
85
  /** The def's theme tokens as `renderCertBlock` theme input, with the accent ink derived. */
@@ -171,3 +177,46 @@ export function envelopeCardInput(
171
177
  },
172
178
  }
173
179
  }
180
+
181
+ /** The def `face` that selects the certrev.com reader face (1.2.0). Nothing else does. */
182
+ export const READER_FACE = 'reader'
183
+
184
+ /** Whether a def asks for the reader face: `face === 'reader'`, exactly. Absent or any other value is the legacy face. */
185
+ export function isReaderFaceDef(def: CertChromeRenderDef | null | undefined): boolean {
186
+ return def?.face === READER_FACE
187
+ }
188
+
189
+ /**
190
+ * The card's HTML for a verified envelope's content and the brand's def, or '' when nothing paints.
191
+ *
192
+ * THE ONE SELECTION POINT between the two faces, react-free so the portal's preview reaches it too:
193
+ * - `renderDef.face === 'reader'` paints the reader face (`renderReaderFace`), the same bytes as the Shopify reader
194
+ * snippets for the same facts;
195
+ * - EVERY other def (no `face`, `face: 'legacy'`, a face this version has never heard of, no def at all) paints
196
+ * exactly `renderCertBlock(envelopeCardInput(...))`, byte for byte what 1.1.1 paints. An unknown face degrades to
197
+ * the face the page had before, never to nothing and never to the reader.
198
+ * The reader branch sits BESIDE the legacy one; `envelopeCardInput` and `renderCertBlock` are not touched.
199
+ *
200
+ * Both faces keep the one gate they share: a content with no reviewer name or no certificate URL cannot make a face.
201
+ * The reader's layout is `layoutFor` (an editor mode wins, then the def's own layout, else banner); the legacy-only
202
+ * `custom` composition has no reader twin and paints the reader banner.
203
+ */
204
+ export function envelopeCardHtml(
205
+ content: CertContent,
206
+ renderDef: CertChromeRenderDef | null,
207
+ options: EnvelopeCardOptions = {},
208
+ ): string {
209
+ const input = envelopeCardInput(content, renderDef, options)
210
+ if (!input) return ''
211
+ if (!isReaderFaceDef(renderDef)) return renderCertBlock(input)
212
+ const chosen = layoutFor(renderDef, options.mode)
213
+ const layout: ReaderLayout = chosen === 'custom' ? 'banner' : chosen
214
+ return renderReaderFace({
215
+ content,
216
+ def: renderDef,
217
+ layout,
218
+ part: input.part,
219
+ certId: typeof options.certId === 'string' ? options.certId : undefined,
220
+ illustrative: options.illustrative === true,
221
+ })
222
+ }
@@ -174,8 +174,11 @@ export {
174
174
  CERT_FACE_FIELDS,
175
175
  credentialLabel,
176
176
  type EnvelopeCardOptions,
177
+ envelopeCardHtml,
177
178
  envelopeCardInput,
178
179
  faceFromDef,
180
+ isReaderFaceDef,
179
181
  layoutFor,
182
+ READER_FACE,
180
183
  themeFromDef,
181
184
  } from './envelope-face.js'
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `certrev-reader-face`: the round avatar on a reader byline: the person's photo when there is one to show, the
3
+ * silhouette when there is not. The span carries a size class (`sm` for the author, none for the banner reviewer,
4
+ * `lg` for the memo and sidebar reviewer); the image is requested at `width` square through the asset resizer.
5
+ */
6
+ import { avatarUrl, cleaned, esc, safeUrl } from './helpers.js'
7
+
8
+ export type ReaderFaceSize = '' | 'sm' | 'lg'
9
+
10
+ export interface ReaderFaceInput {
11
+ /** The photo URL on the envelope. */
12
+ readonly photo: unknown
13
+ /** Whether to ATTEMPT the photo: false never reads the URL (the silhouette shows). */
14
+ readonly show: boolean
15
+ readonly size: ReaderFaceSize
16
+ /** The pixel width the resizer is asked for. */
17
+ readonly width: number
18
+ }
19
+
20
+ const SILHOUETTE =
21
+ '<svg viewBox="0 0 40 40" aria-hidden="true" focusable="false"><circle cx="20" cy="14.8" r="7"/><path d="M20 23.4c-6.9 0-12.6 4.8-13.8 11.2a20 20 0 0 0 27.6 0C32.6 28.2 26.9 23.4 20 23.4Z"/></svg>'
22
+
23
+ const DIMENSION: Readonly<Record<ReaderFaceSize, number>> = { '': 42, sm: 36, lg: 46 }
24
+
25
+ export function readerFace({ photo, show, size, width }: ReaderFaceInput): string {
26
+ const safe = show ? cleaned(safeUrl(photo)) : ''
27
+ const src = cleaned(avatarUrl(safe, width))
28
+ const dim = DIMENSION[size]
29
+ const cls = size === '' ? 'certrev-r-face' : `certrev-r-face ${esc(size)}`
30
+ const inner =
31
+ src !== ''
32
+ ? `<img src="${esc(src)}" alt="" width="${dim}" height="${dim}" loading="lazy" decoding="async">`
33
+ : SILHOUETTE
34
+ return `<span class="${cls}">${inner}</span>`
35
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * The Liquid semantics the reader snippets lean on, as small pure functions.
3
+ *
4
+ * The reader face is a byte-for-byte twin of the Shopify `certrev-reader-*` snippets, so the helpers below are not
5
+ * "what a TypeScript author would write": each one reproduces what the Liquid filter or tag does with the same input
6
+ * (which value counts as `blank`, which `default` replaces, how `contains` reads a string, what `strip_html` removes).
7
+ * Where the snippets call another snippet (`certrev-safe-url`, `certrev-avatar-url`, `certrev-reader-first-name`,
8
+ * `certrev-reader-date`) the port is named for it.
9
+ *
10
+ * Like every helper in this package they NEVER throw on a hostile type: the envelope is verified for its signature,
11
+ * not its shape, so a number or an object can arrive where the contract promised a string. Values are read through
12
+ * `rec` and `asText`, never dereferenced bare.
13
+ */
14
+ import { asText, escapeHtml } from '../components/escape.js'
15
+
16
+ export type Rec = Readonly<Record<string, unknown>>
17
+
18
+ const NO_FIELDS: Rec = Object.freeze({})
19
+
20
+ /** An object's fields, or none: Liquid reads a missing field as nil, never an error. */
21
+ export function rec(value: unknown): Rec {
22
+ return typeof value === 'object' && value !== null && !Array.isArray(value) ? (value as Rec) : NO_FIELDS
23
+ }
24
+
25
+ /** Liquid `escape` as Shopify (and this package) spell it: `&amp; &lt; &gt; &quot; &#39;`. */
26
+ export const esc = (value: unknown): string => escapeHtml(asText(value))
27
+
28
+ /** Liquid `default: fallback`: replaces nil, false and the empty string only (whitespace stays). */
29
+ export function orDefault(value: unknown, fallback: string): unknown {
30
+ return value === undefined || value === null || value === false || value === '' ? fallback : value
31
+ }
32
+
33
+ /** `value | default: ''` read as text. */
34
+ export const textOr = (value: unknown, fallback = ''): string => asText(orDefault(value, fallback))
35
+
36
+ /** Liquid's `== blank` for the string-ish values the envelope carries: nil, false, empty or whitespace only. */
37
+ export const isBlank = (value: unknown): boolean => asText(value).trim() === ''
38
+
39
+ /** `{% if x %}` for a value read as a flag: Liquid treats only nil and false as false (the empty string is true). */
40
+ export const isTruthy = (value: unknown): boolean => value !== undefined && value !== null && value !== false
41
+
42
+ /** Whether a field carries a value after `| default: ''` (so `!= ''` in the snippet). */
43
+ export const isPresent = (value: unknown): boolean =>
44
+ !(value === undefined || value === null || value === false || value === '')
45
+
46
+ /** Liquid `contains`: an array holds the needle, a string includes it, anything else does not. */
47
+ export function contains(container: unknown, needle: string): boolean {
48
+ if (Array.isArray(container)) return container.some((item) => item === needle)
49
+ if (typeof container === 'string') return container.includes(needle)
50
+ return false
51
+ }
52
+
53
+ /**
54
+ * Liquid `strip_html` as the portal's liquidjs harness runs it: raw-text blocks (`<script…</script>`, `<style…</style>`,
55
+ * `<!-- … -->`) and then any `<…>` tag are dropped; an opener with no closer is not a block, and once no opener fits
56
+ * the rest of the string is kept as it is. The snippets use it on every captured value because Shopify wraps each
57
+ * `{% render %}` of an app snippet in `<!-- BEGIN/END app snippet -->` comments that would corrupt an attribute.
58
+ */
59
+ export function stripHtml(input: string): string {
60
+ const blocks = new Map<string, string>([
61
+ ['<script', '</script>'],
62
+ ['<style', '</style>'],
63
+ ['<!--', '-->'],
64
+ ['<', '>'],
65
+ ])
66
+ let out = ''
67
+ let i = 0
68
+ while (i < input.length) {
69
+ const lt = input.indexOf('<', i)
70
+ if (lt < 0) return out + input.slice(i)
71
+ out += input.slice(i, lt)
72
+ for (const [opener, closer] of blocks) {
73
+ if (!input.startsWith(opener, lt)) continue
74
+ const end = input.indexOf(closer, lt + opener.length)
75
+ if (end >= 0) {
76
+ i = end + closer.length
77
+ break
78
+ }
79
+ blocks.delete(opener)
80
+ }
81
+ if (i <= lt) return out + input.slice(lt)
82
+ }
83
+ return out
84
+ }
85
+
86
+ /** `{% capture x %}…{% endcapture %}` then `x | strip_html | strip`, which every snippet applies to a captured value. */
87
+ export const cleaned = (value: string): string => stripHtml(value).trim()
88
+
89
+ /**
90
+ * `certrev-safe-url`: the trimmed URL when it is http(s), protocol-relative or site-relative (`/…`, `#…`), else ''.
91
+ * A `javascript:`, `data:` or other scheme collapses to '' so the caller's `!= ''` guard drops the link or the photo.
92
+ */
93
+ export function safeUrl(url: unknown): string {
94
+ const u = textOr(url).trim()
95
+ if (u === '') return ''
96
+ const lower = u.toLowerCase()
97
+ if (
98
+ lower.startsWith('https://') ||
99
+ lower.startsWith('http://') ||
100
+ u.startsWith('//') ||
101
+ u.startsWith('/') ||
102
+ u.startsWith('#')
103
+ )
104
+ return u
105
+ return ''
106
+ }
107
+
108
+ const ASSET_HOSTS: readonly string[] = ['assets.certrev.com', 'staging-assets.certrev.com']
109
+
110
+ /**
111
+ * `certrev-avatar-url`: a CertREV asset-host photo is requested through the host's `cdn-cgi/image` resizer at
112
+ * `width` square (the query string dropped, which the WAF allowlist pins to empty); any other URL, a lookalike host,
113
+ * an `http://` or `//` form, or a URL already carrying `cdn-cgi/image/`, is returned as it is.
114
+ */
115
+ export function avatarUrl(url: string, width: number): string {
116
+ const u = url.trim()
117
+ if (!u.includes('assets.certrev.com/')) return u
118
+ const after = u.replace('https://', '')
119
+ const host = after.split('/')[0] ?? ''
120
+ if (!ASSET_HOSTS.includes(host)) return u
121
+ const path = after.replace(host, '').replace('/', '').split('?')[0] ?? ''
122
+ if (path.includes('cdn-cgi/image/')) return u
123
+ return `https://${host}/cdn-cgi/image/width=${width},height=${width},fit=cover,format=auto,onerror=redirect/${path}`
124
+ }
125
+
126
+ const HONORIFICS: readonly string[] = [
127
+ 'dr.',
128
+ 'dr',
129
+ 'mr.',
130
+ 'mr',
131
+ 'mrs.',
132
+ 'mrs',
133
+ 'ms.',
134
+ 'ms',
135
+ 'prof.',
136
+ 'prof',
137
+ 'mx.',
138
+ 'mx',
139
+ ]
140
+
141
+ /**
142
+ * `certrev-reader-first-name`: the name's first word with a leading honorific (Dr., Mr., Mrs., Ms., Prof., Mx.,
143
+ * any case) dropped; '' when nothing is left, which the caller words as "View profile".
144
+ */
145
+ export function firstName(name: string): string {
146
+ let clean = name.trim()
147
+ const firstWord = (clean.split(' ')[0] ?? '').toLowerCase()
148
+ if (HONORIFICS.includes(firstWord)) {
149
+ const honorific = clean.split(' ')[0] ?? ''
150
+ clean = clean.replace(honorific, '').trim()
151
+ }
152
+ return clean.split(' ')[0] ?? ''
153
+ }
154
+
155
+ const MONTHS: readonly string[] = [
156
+ 'January',
157
+ 'February',
158
+ 'March',
159
+ 'April',
160
+ 'May',
161
+ 'June',
162
+ 'July',
163
+ 'August',
164
+ 'September',
165
+ 'October',
166
+ 'November',
167
+ 'December',
168
+ ]
169
+
170
+ /**
171
+ * `certrev-reader-date`: "June 20, 2026" for an ISO timestamp, read in UTC (the portal harness's `date` filter does
172
+ * the same). A value that is not a date prints nothing, so the caller's `!= ''` guard falls to the undated wording.
173
+ */
174
+ export function longDate(iso: unknown): string {
175
+ const parsed = new Date(asText(iso))
176
+ if (Number.isNaN(parsed.getTime())) return ''
177
+ return `${MONTHS[parsed.getUTCMonth()]} ${parsed.getUTCDate()}, ${parsed.getUTCFullYear()}`
178
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The reader face, react-free: `@certrev/cert-block/reader`.
3
+ *
4
+ * Importing this loads no React, so a server bundle that cannot load `./builder` (it creates a React context at import)
5
+ * can still render, and a stylesheet pipeline can still read the CSS. The Builder card reaches the same function
6
+ * through `envelopeCardHtml` (`./builder/face`); the stylesheet is also the package asset `./reader.css`.
7
+ */
8
+ export { READER_CSS } from './reader-css.generated.js'
9
+ export {
10
+ type ReaderFaceInput,
11
+ type ReaderLayout,
12
+ type ReaderPart,
13
+ renderReaderFace,
14
+ } from './render.js'
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The CertREV mark the reader face paints in the card cap (18px) and the memo footer (17px): the Liquid
3
+ * `certrev-reader-logo` snippet's inline SVG data URI, byte for byte, so a Builder page and a Shopify page carry the
4
+ * same image. White on a dark accent, black (the demo's logo-mono) on a light one.
5
+ *
6
+ * The four `d` strings below are the snippet's, copied rather than retyped; the golden tests compare the whole
7
+ * element, so a slipped digit fails there.
8
+ */
9
+ import { escapeHtml } from '../components/escape.js'
10
+
11
+ export type ReaderLogoInk = 'white' | 'mono'
12
+
13
+ const MARK_PATHS: readonly string[] = [
14
+ 'M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z',
15
+ 'M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z',
16
+ 'M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z',
17
+ 'M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z',
18
+ ]
19
+
20
+ /** The `<img>` for the mark: `size` is the pixel width and height, `alt` is '' where the words carry the meaning. */
21
+ export function readerLogo(ink: ReaderLogoInk, size: number, alt: string): string {
22
+ const fill = ink === 'white' ? 'ffffff' : '000000'
23
+ const paths = MARK_PATHS.map((d) => `%3Cpath fill='%23${fill}' d='${d}'/%3E`).join('')
24
+ return (
25
+ `<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 375 375'%3E${paths}%3C/svg%3E" ` +
26
+ `alt="${escapeHtml(alt)}" width="${escapeHtml(String(size))}" height="${escapeHtml(String(size))}" decoding="async">`
27
+ )
28
+ }