@cogenta/theme-canonical 0.2.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/src/index.d.ts +4 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +4 -0
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/render/actions.d.ts +2 -16
  6. package/dist/src/render/actions.d.ts.map +1 -1
  7. package/dist/src/render/actions.js +2 -42
  8. package/dist/src/render/actions.js.map +1 -1
  9. package/dist/src/render/blocks/accordion.d.ts +5 -0
  10. package/dist/src/render/blocks/accordion.d.ts.map +1 -0
  11. package/dist/src/render/blocks/accordion.js +19 -0
  12. package/dist/src/render/blocks/accordion.js.map +1 -0
  13. package/dist/src/render/blocks/collection-list.d.ts +9 -7
  14. package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
  15. package/dist/src/render/blocks/collection-list.js +8 -14
  16. package/dist/src/render/blocks/collection-list.js.map +1 -1
  17. package/dist/src/render/blocks/feature-grid.d.ts.map +1 -1
  18. package/dist/src/render/blocks/feature-grid.js +7 -2
  19. package/dist/src/render/blocks/feature-grid.js.map +1 -1
  20. package/dist/src/render/blocks/logo-strip.d.ts +5 -0
  21. package/dist/src/render/blocks/logo-strip.d.ts.map +1 -0
  22. package/dist/src/render/blocks/logo-strip.js +18 -0
  23. package/dist/src/render/blocks/logo-strip.js.map +1 -0
  24. package/dist/src/render/blocks/pricing-table.d.ts +5 -0
  25. package/dist/src/render/blocks/pricing-table.d.ts.map +1 -0
  26. package/dist/src/render/blocks/pricing-table.js +29 -0
  27. package/dist/src/render/blocks/pricing-table.js.map +1 -0
  28. package/dist/src/render/blocks/stat-counter.d.ts +5 -0
  29. package/dist/src/render/blocks/stat-counter.d.ts.map +1 -0
  30. package/dist/src/render/blocks/stat-counter.js +17 -0
  31. package/dist/src/render/blocks/stat-counter.js.map +1 -0
  32. package/dist/src/render/blocks/testimonial.d.ts +14 -0
  33. package/dist/src/render/blocks/testimonial.d.ts.map +1 -0
  34. package/dist/src/render/blocks/testimonial.js +24 -0
  35. package/dist/src/render/blocks/testimonial.js.map +1 -0
  36. package/dist/src/render/chrome.d.ts +3 -0
  37. package/dist/src/render/chrome.d.ts.map +1 -0
  38. package/dist/src/render/chrome.js +82 -0
  39. package/dist/src/render/chrome.js.map +1 -0
  40. package/dist/src/render/comments.d.ts +3 -0
  41. package/dist/src/render/comments.d.ts.map +1 -0
  42. package/dist/src/render/comments.js +3 -0
  43. package/dist/src/render/comments.js.map +1 -0
  44. package/dist/src/render/entry.d.ts +2 -6
  45. package/dist/src/render/entry.d.ts.map +1 -1
  46. package/dist/src/render/entry.js +2 -34
  47. package/dist/src/render/entry.js.map +1 -1
  48. package/dist/src/render/heading.d.ts +2 -13
  49. package/dist/src/render/heading.d.ts.map +1 -1
  50. package/dist/src/render/heading.js +2 -33
  51. package/dist/src/render/heading.js.map +1 -1
  52. package/dist/src/render/html.d.ts +2 -43
  53. package/dist/src/render/html.d.ts.map +1 -1
  54. package/dist/src/render/html.js +2 -95
  55. package/dist/src/render/html.js.map +1 -1
  56. package/dist/src/render/icons.d.ts +3 -0
  57. package/dist/src/render/icons.d.ts.map +1 -0
  58. package/dist/src/render/icons.js +3 -0
  59. package/dist/src/render/icons.js.map +1 -0
  60. package/dist/src/render/media.d.ts +2 -31
  61. package/dist/src/render/media.d.ts.map +1 -1
  62. package/dist/src/render/media.js +2 -41
  63. package/dist/src/render/media.js.map +1 -1
  64. package/dist/src/render/render-block.d.ts +11 -22
  65. package/dist/src/render/render-block.d.ts.map +1 -1
  66. package/dist/src/render/render-block.js +63 -62
  67. package/dist/src/render/render-block.js.map +1 -1
  68. package/dist/src/render/rich-text.d.ts +2 -4
  69. package/dist/src/render/rich-text.d.ts.map +1 -1
  70. package/dist/src/render/rich-text.js +2 -104
  71. package/dist/src/render/rich-text.js.map +1 -1
  72. package/dist/src/render/term-archive.d.ts +12 -0
  73. package/dist/src/render/term-archive.d.ts.map +1 -0
  74. package/dist/src/render/term-archive.js +39 -0
  75. package/dist/src/render/term-archive.js.map +1 -0
  76. package/dist/src/theme-contract.d.ts +10 -162
  77. package/dist/src/theme-contract.d.ts.map +1 -1
  78. package/dist/src/theme-contract.js +9 -17
  79. package/dist/src/theme-contract.js.map +1 -1
  80. package/dist/theme.config.d.ts +5 -16
  81. package/dist/theme.config.d.ts.map +1 -1
  82. package/dist/theme.config.js +16 -5
  83. package/dist/theme.config.js.map +1 -1
  84. package/package.json +4 -2
  85. package/src/index.ts +4 -0
  86. package/src/render/actions.ts +2 -57
  87. package/src/render/blocks/accordion.ts +44 -0
  88. package/src/render/blocks/collection-list.ts +9 -15
  89. package/src/render/blocks/feature-grid.ts +11 -2
  90. package/src/render/blocks/logo-strip.ts +38 -0
  91. package/src/render/blocks/pricing-table.ts +65 -0
  92. package/src/render/blocks/stat-counter.ts +34 -0
  93. package/src/render/blocks/testimonial.ts +41 -0
  94. package/src/render/chrome.ts +105 -0
  95. package/src/render/comments.ts +6 -0
  96. package/src/render/entry.ts +2 -40
  97. package/src/render/heading.ts +7 -44
  98. package/src/render/html.ts +15 -122
  99. package/src/render/icons.ts +2 -0
  100. package/src/render/media.ts +2 -62
  101. package/src/render/render-block.ts +85 -75
  102. package/src/render/rich-text.ts +2 -150
  103. package/src/render/term-archive.ts +85 -0
  104. package/src/styles/archive.css +40 -0
  105. package/src/styles/base.css +525 -3
  106. package/src/styles/blocks.css +344 -14
  107. package/src/styles/theme.css +1 -0
  108. package/src/theme-contract.ts +23 -155
@@ -1 +1 @@
1
- {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../src/render/entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAavE,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAM1E;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAMpE;AAED,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAGjE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAEzE"}
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../src/render/entry.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,35 +1,3 @@
1
- /**
2
- * Contract A fixes the system fields but not the schema-defined ones: which
3
- * fields an entry has depends on its collection, and a theme that assumes
4
- * `title` exists breaks on the first collection that calls it `name`.
5
- *
6
- * So every read of an unknown field goes through here, returns a fallback the
7
- * visitor can live with, and never renders `undefined`.
8
- */
9
- const TITLE_FIELDS = ['title', 'name', 'label'];
10
- export function entryTitle(entry, ctx) {
11
- for (const field of TITLE_FIELDS) {
12
- const value = entry[field];
13
- if (typeof value === 'string' && value.trim() !== '')
14
- return value;
15
- }
16
- return ctx.t('entry.untitled');
17
- }
18
- const EXCERPT_FIELDS = ['excerpt', 'summary', 'description'];
19
- export function entryExcerpt(entry) {
20
- for (const field of EXCERPT_FIELDS) {
21
- const value = entry[field];
22
- if (typeof value === 'string' && value.trim() !== '')
23
- return value;
24
- }
25
- return undefined;
26
- }
27
- /** ISO 8601, for `<time datetime>`. Anything else is not a date this can use. */
28
- export function entryDate(entry) {
29
- const value = entry.publishedAt ?? entry.createdAt;
30
- return typeof value === 'string' && !Number.isNaN(Date.parse(value)) ? value : undefined;
31
- }
32
- export function entryHref(entry, ctx) {
33
- return ctx.link({ collection: entry.collection, id: entry.id });
34
- }
1
+ /** Re-exported from `@cogenta/theme-kit` — see that package's `entry.ts`. */
2
+ export { entryDate, entryExcerpt, entryHref, entryImage, entryTitle } from '@cogenta/theme-kit';
35
3
  //# sourceMappingURL=entry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../src/render/entry.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA;AAExD,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,GAAkB;IAChE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,KAAK,CAAA;IACpE,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAA;AAChC,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,CAAU,CAAA;AAErE,MAAM,UAAU,YAAY,CAAC,KAAmB;IAC9C,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,KAAK,CAAA;IACpE,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,KAAmB;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,SAAS,CAAA;IAClD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAC1F,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAmB,EAAE,GAAkB;IAC/D,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAA;AACjE,CAAC"}
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../src/render/entry.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,14 +1,3 @@
1
- import { type Child, type HtmlElement } from './html.js';
2
- export type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
3
- /** The level a block's own title is rendered at, or `null` if it carries none. */
4
- export declare function blockHeadingTag(blockName: string): HeadingTag | null;
5
- /**
6
- * The level for a title *inside* a block — a feature's name, a listed entry.
7
- *
8
- * One below the block's own heading when the block renders one, and at the
9
- * block's declared level when it does not: a `featureGrid` without a title must
10
- * not start its items at `h3`, which would skip a level.
11
- */
12
- export declare function nestedHeadingTag(blockName: string, blockRendersHeading: boolean): HeadingTag;
13
- export declare function heading(tag: HeadingTag, attrs: Readonly<Record<string, string | number | boolean | undefined>>, ...children: readonly Child[]): HtmlElement;
1
+ /** Re-exported from `@cogenta/theme-kit` see that package's `heading.ts`. */
2
+ export { blockHeadingTag, type HeadingTag, heading, nestedHeadingTag, } from '@cogenta/theme-kit';
14
3
  //# sourceMappingURL=heading.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../../../src/render/heading.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,WAAW,EAAK,MAAM,WAAW,CAAA;AAY3D,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEhE,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAIpE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,mBAAmB,EAAE,OAAO,GAAG,UAAU,CAK5F;AAED,wBAAgB,OAAO,CACrB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC,EACtE,GAAG,QAAQ,EAAE,SAAS,KAAK,EAAE,GAC5B,WAAW,CAEb"}
1
+ {"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../../../src/render/heading.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EACL,eAAe,EACf,KAAK,UAAU,EACf,OAAO,EACP,gBAAgB,GACjB,MAAM,oBAAoB,CAAA"}
@@ -1,34 +1,3 @@
1
- import { VOCABULARY } from '@cogenta/blocks';
2
- import { h } from './html.js';
3
- /**
4
- * The heading level of a block is **not** a theme decision: contract B fixes it
5
- * in each block's `a11y.headingLevel`, and the theme reads it from there rather
6
- * than restating it. Restating it is how an outline drifts — one block gets
7
- * promoted in the theme, the page grows a second `h1`, and nothing fails.
8
- */
9
- const DECLARED_LEVELS = new Map(VOCABULARY.map((block) => [block.name, block.a11y.headingLevel]));
10
- /** The level a block's own title is rendered at, or `null` if it carries none. */
11
- export function blockHeadingTag(blockName) {
12
- const level = DECLARED_LEVELS.get(blockName);
13
- if (level === undefined || level === 'none')
14
- return null;
15
- return level;
16
- }
17
- /**
18
- * The level for a title *inside* a block — a feature's name, a listed entry.
19
- *
20
- * One below the block's own heading when the block renders one, and at the
21
- * block's declared level when it does not: a `featureGrid` without a title must
22
- * not start its items at `h3`, which would skip a level.
23
- */
24
- export function nestedHeadingTag(blockName, blockRendersHeading) {
25
- const own = blockHeadingTag(blockName) ?? 'h2';
26
- if (!blockRendersHeading)
27
- return own;
28
- const next = Number(own.slice(1)) + 1;
29
- return `h${Math.min(next, 6)}`;
30
- }
31
- export function heading(tag, attrs, ...children) {
32
- return h(tag, attrs, ...children);
33
- }
1
+ /** Re-exported from `@cogenta/theme-kit` — see that package's `heading.ts`. */
2
+ export { blockHeadingTag, heading, nestedHeadingTag, } from '@cogenta/theme-kit';
34
3
  //# sourceMappingURL=heading.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"heading.js","sourceRoot":"","sources":["../../../src/render/heading.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAgC,CAAC,EAAE,MAAM,WAAW,CAAA;AAE3D;;;;;GAKG;AACH,MAAM,eAAe,GAAsC,IAAI,GAAG,CAChE,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CACjE,CAAA;AAID,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC5C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IACxD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,mBAA4B;IAC9E,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,IAAI,CAAA;IAC9C,IAAI,CAAC,mBAAmB;QAAE,OAAO,GAAG,CAAA;IACpC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACrC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EAAgB,CAAA;AAC9C,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,GAAe,EACf,KAAsE,EACtE,GAAG,QAA0B;IAE7B,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAA;AACnC,CAAC"}
1
+ {"version":3,"file":"heading.js","sourceRoot":"","sources":["../../../src/render/heading.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EACL,eAAe,EAEf,OAAO,EACP,gBAAgB,GACjB,MAAM,oBAAoB,CAAA"}
@@ -1,44 +1,3 @@
1
- /**
2
- * A minimal, dependency-free HTML tree and serialiser.
3
- *
4
- * Why the theme's markup is built here rather than written inline in the
5
- * `.astro` files:
6
- *
7
- * 1. It is testable without an Astro toolchain — the twelve blocks get real
8
- * snapshot tests, and the heading outline and the `alt` rule get asserted on
9
- * the actual output rather than on a reading of the source.
10
- * 2. There is **no way to emit raw HTML**. A block stores semantic data only
11
- * (rule R3); with no `raw()` escape hatch, a string that arrives in a block
12
- * field cannot become markup, whatever it contains.
13
- *
14
- * The `.astro` components in `src/blocks/` are the contract-D entry points and
15
- * stay thin on purpose: one call each, so the two never drift.
16
- */
17
- export type AttributeValue = string | number | boolean | undefined;
18
- export type Attributes = Readonly<Record<string, AttributeValue>>;
19
- export interface HtmlElement {
20
- readonly kind: 'element';
21
- readonly tag: string;
22
- readonly attrs: Attributes;
23
- readonly children: readonly HtmlNode[];
24
- }
25
- export interface HtmlText {
26
- readonly kind: 'text';
27
- readonly value: string;
28
- }
29
- export type HtmlNode = HtmlElement | HtmlText;
30
- /** Anything a caller may pass as a child. `null`/`false` drop out, so a
31
- * conditional child reads as `condition && node` without a wrapper. */
32
- export type Child = HtmlNode | string | null | false | undefined | readonly Child[];
33
- export declare function text(value: string): HtmlText;
34
- export declare function h(tag: string, attrs?: Attributes, ...children: readonly Child[]): HtmlElement;
35
- /**
36
- * `&` first, or every following replacement would be escaped twice.
37
- * `<` and `>` cover text; the quotes are escaped in attributes only, where they
38
- * are the ones that can break out.
39
- */
40
- export declare function escapeText(value: string): string;
41
- export declare function escapeAttribute(value: string): string;
42
- export declare function serialize(node: HtmlNode): string;
43
- export declare function serializeAll(nodes: readonly HtmlNode[]): string;
1
+ /** Re-exported from `@cogenta/theme-kit` — see that package's `html.ts`. */
2
+ export { type Attributes, type AttributeValue, type Child, escapeAttribute, escapeText, type HtmlElement, type HtmlNode, type HtmlText, h, serialize, serializeAll, text, } from '@cogenta/theme-kit';
44
3
  //# sourceMappingURL=html.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/render/html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;AAElE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAEjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,QAAQ,EAAE,CAAA;CACvC;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,QAAQ,CAAA;AAE7C;uEACuE;AACvE,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,KAAK,EAAE,CAAA;AAsBnF,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE5C;AAiBD,wBAAgB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,UAAe,EAAE,GAAG,QAAQ,EAAE,SAAS,KAAK,EAAE,GAAG,WAAW,CAIjG;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD;AAiBD,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAKhD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAE/D"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../src/render/html.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EACL,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,KAAK,EACV,eAAe,EACf,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,CAAC,EACD,SAAS,EACT,YAAY,EACZ,IAAI,GACL,MAAM,oBAAoB,CAAA"}
@@ -1,96 +1,3 @@
1
- /**
2
- * A minimal, dependency-free HTML tree and serialiser.
3
- *
4
- * Why the theme's markup is built here rather than written inline in the
5
- * `.astro` files:
6
- *
7
- * 1. It is testable without an Astro toolchain — the twelve blocks get real
8
- * snapshot tests, and the heading outline and the `alt` rule get asserted on
9
- * the actual output rather than on a reading of the source.
10
- * 2. There is **no way to emit raw HTML**. A block stores semantic data only
11
- * (rule R3); with no `raw()` escape hatch, a string that arrives in a block
12
- * field cannot become markup, whatever it contains.
13
- *
14
- * The `.astro` components in `src/blocks/` are the contract-D entry points and
15
- * stay thin on purpose: one call each, so the two never drift.
16
- */
17
- /**
18
- * Elements that carry no children and no closing tag. Serialising `<img>` with
19
- * one would produce markup no parser agrees on.
20
- */
21
- const VOID_ELEMENTS = new Set([
22
- 'area',
23
- 'base',
24
- 'br',
25
- 'col',
26
- 'embed',
27
- 'hr',
28
- 'img',
29
- 'input',
30
- 'link',
31
- 'meta',
32
- 'source',
33
- 'track',
34
- 'wbr',
35
- ]);
36
- export function text(value) {
37
- return { kind: 'text', value };
38
- }
39
- function flatten(children, into) {
40
- for (const child of children) {
41
- if (child === null || child === false || child === undefined)
42
- continue;
43
- if (typeof child === 'string') {
44
- into.push(text(child));
45
- continue;
46
- }
47
- if (Array.isArray(child)) {
48
- flatten(child, into);
49
- continue;
50
- }
51
- into.push(child);
52
- }
53
- }
54
- export function h(tag, attrs = {}, ...children) {
55
- const collected = [];
56
- flatten(children, collected);
57
- return { kind: 'element', tag, attrs, children: collected };
58
- }
59
- /**
60
- * `&` first, or every following replacement would be escaped twice.
61
- * `<` and `>` cover text; the quotes are escaped in attributes only, where they
62
- * are the ones that can break out.
63
- */
64
- export function escapeText(value) {
65
- return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
66
- }
67
- export function escapeAttribute(value) {
68
- return escapeText(value).replace(/"/g, '&quot;').replace(/'/g, '&#39;');
69
- }
70
- function serializeAttributes(attrs) {
71
- let out = '';
72
- // Insertion order, not sorted: it is deterministic already, and an author
73
- // reading a snapshot expects the order they wrote.
74
- for (const [name, value] of Object.entries(attrs)) {
75
- if (value === undefined || value === false)
76
- continue;
77
- if (value === true) {
78
- out += ` ${name}`;
79
- continue;
80
- }
81
- out += ` ${name}="${escapeAttribute(String(value))}"`;
82
- }
83
- return out;
84
- }
85
- export function serialize(node) {
86
- if (node.kind === 'text')
87
- return escapeText(node.value);
88
- const open = `<${node.tag}${serializeAttributes(node.attrs)}>`;
89
- if (VOID_ELEMENTS.has(node.tag))
90
- return open;
91
- return `${open}${node.children.map(serialize).join('')}</${node.tag}>`;
92
- }
93
- export function serializeAll(nodes) {
94
- return nodes.map(serialize).join('');
95
- }
1
+ /** Re-exported from `@cogenta/theme-kit` — see that package's `html.ts`. */
2
+ export { escapeAttribute, escapeText, h, serialize, serializeAll, text, } from '@cogenta/theme-kit';
96
3
  //# sourceMappingURL=html.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../src/render/html.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../src/render/html.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAIL,eAAe,EACf,UAAU,EAIV,CAAC,EACD,SAAS,EACT,YAAY,EACZ,IAAI,GACL,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Re-exported from `@cogenta/theme-kit` — see that package's `icons.ts`. */
2
+ export { ICON_NAMES, type IconName, renderIcon } from '@cogenta/theme-kit';
3
+ //# sourceMappingURL=icons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../../src/render/icons.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Re-exported from `@cogenta/theme-kit` — see that package's `icons.ts`. */
2
+ export { ICON_NAMES, renderIcon } from '@cogenta/theme-kit';
3
+ //# sourceMappingURL=icons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icons.js","sourceRoot":"","sources":["../../../src/render/icons.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,UAAU,EAAiB,UAAU,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,32 +1,3 @@
1
- import type { ImageOptions, MediaReference, RenderContext } from '../theme-contract.js';
2
- import { type HtmlElement } from './html.js';
3
- export interface ImageRenderOptions {
4
- /** The `sizes` hint. Layout knowledge, so it belongs to the theme, not the block. */
5
- readonly sizes?: string;
6
- /** `eager` only for what is above the fold — the hero, and nothing else. */
7
- readonly loading?: 'lazy' | 'eager';
8
- readonly className?: string;
9
- /**
10
- * An accessible name the *block* provides — a logo's organisation name, for
11
- * instance. It never invents alt text: it is used only where contract B says
12
- * the block already carries the name.
13
- */
14
- readonly altFrom?: string;
15
- readonly variant?: ImageOptions;
16
- }
17
- /**
18
- * The only place the theme emits an `<img>`.
19
- *
20
- * `alt` is always written, never omitted: an image with no `alt` attribute is
21
- * announced by its file name, while `alt=""` is announced as decorative. The
22
- * difference is the whole of WCAG 1.1.1 here, and it cannot be left to whether
23
- * a caller remembered.
24
- *
25
- * The alt text itself comes from the media entity through `ctx.image` — the
26
- * theme has no business inventing one, and correcting it in the media library
27
- * must fix every page at once.
28
- */
29
- export declare function image(ctx: RenderContext, media: MediaReference, options?: ImageRenderOptions): HtmlElement;
30
- /** Contract B's framing values, as a CSS `aspect-ratio`. `original` means none. */
31
- export declare function aspectRatio(ratio: string | undefined): string | undefined;
1
+ /** Re-exported from `@cogenta/theme-kit` see that package's `media.ts`. */
2
+ export { aspectRatio, type ImageRenderOptions, image } from '@cogenta/theme-kit';
32
3
  //# sourceMappingURL=media.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/render/media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EAAE,KAAK,WAAW,EAAK,MAAM,WAAW,CAAA;AAE/C,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAChC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CACnB,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,kBAAuB,GAC/B,WAAW,CAmBb;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKzE"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/render/media.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,42 +1,3 @@
1
- import { h } from './html.js';
2
- /**
3
- * The only place the theme emits an `<img>`.
4
- *
5
- * `alt` is always written, never omitted: an image with no `alt` attribute is
6
- * announced by its file name, while `alt=""` is announced as decorative. The
7
- * difference is the whole of WCAG 1.1.1 here, and it cannot be left to whether
8
- * a caller remembered.
9
- *
10
- * The alt text itself comes from the media entity through `ctx.image` — the
11
- * theme has no business inventing one, and correcting it in the media library
12
- * must fix every page at once.
13
- */
14
- export function image(ctx, media, options = {}) {
15
- const source = ctx.image(media, options.variant);
16
- return h('img', {
17
- class: options.className,
18
- src: source.src,
19
- srcset: source.srcset === '' ? undefined : source.srcset,
20
- sizes: options.sizes,
21
- width: source.width,
22
- height: source.height,
23
- alt: source.alt !== '' ? source.alt : (options.altFrom ?? ''),
24
- loading: options.loading ?? 'lazy',
25
- decoding: 'async',
26
- // The focal point is content data, not a style value: it says which part of
27
- // the picture must survive a crop. Nothing else can carry it per-image.
28
- style: source.focal === null
29
- ? undefined
30
- : `object-position:${source.focal.x * 100}% ${source.focal.y * 100}%`,
31
- });
32
- }
33
- /** Contract B's framing values, as a CSS `aspect-ratio`. `original` means none. */
34
- export function aspectRatio(ratio) {
35
- if (ratio === undefined || ratio === 'original')
36
- return undefined;
37
- const [width, height] = ratio.split(':');
38
- if (width === undefined || height === undefined)
39
- return undefined;
40
- return `${width} / ${height}`;
41
- }
1
+ /** Re-exported from `@cogenta/theme-kit` see that package's `media.ts`. */
2
+ export { aspectRatio, image } from '@cogenta/theme-kit';
42
3
  //# sourceMappingURL=media.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/render/media.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,CAAC,EAAE,MAAM,WAAW,CAAA;AAiB/C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,KAAK,CACnB,GAAkB,EAClB,KAAqB,EACrB,OAAO,GAAuB,EAAE;IAEhC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IAChD,OAAO,CAAC,CAAC,KAAK,EAAE;QACd,KAAK,EAAE,OAAO,CAAC,SAAS;QACxB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM;QACxD,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAC7D,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM;QAClC,QAAQ,EAAE,OAAO;QACjB,4EAA4E;QAC5E,wEAAwE;QACxE,KAAK,EACH,MAAM,CAAC,KAAK,KAAK,IAAI;YACnB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,GAAG;KAC1E,CAAC,CAAA;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,SAAS,CAAA;IACjE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACxC,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACjE,OAAO,GAAG,KAAK,MAAM,MAAM,EAAE,CAAA;AAC/B,CAAC"}
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/render/media.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,EAAE,WAAW,EAA2B,KAAK,EAAE,MAAM,oBAAoB,CAAA"}
@@ -1,26 +1,15 @@
1
- import type { VocabularyBlock } from '@cogenta/blocks';
2
- import type { ContentEntry, RenderContext } from '../theme-contract.js';
1
+ import { type BlockRegistry, type VocabularyBlock } from '@cogenta/blocks';
2
+ import { type FetchedEntries, type PageContent, pageHasOwnHeading, renderEntryHeader, withBlockKey } from '@cogenta/theme-kit';
3
+ import type { RenderContext } from '../theme-contract.js';
3
4
  import { type HtmlElement } from './html.js';
4
5
  /**
5
- * Entries already fetched for the `collectionList` blocks on the page, by the
6
- * block's `_key`. Fetching happens in the Astro frontmatter, once per block,
7
- * before any markup is built a renderer that could await would make the
8
- * number of round trips depend on the markup.
6
+ * `PageContent`/`FetchedEntries`/`pageHasOwnHeading`/`withBlockKey` are
7
+ * `@cogenta/theme-kit`'s own re-exported here (rather than only imported)
8
+ * so this package's public surface still names them, exactly as it did
9
+ * before they moved to the package every theme now shares them from.
9
10
  */
10
- export type FetchedEntries = Readonly<Record<string, readonly ContentEntry[]>>;
11
- export declare function renderBlock(block: VocabularyBlock, ctx: RenderContext, entries?: FetchedEntries): HtmlElement | null;
12
- export interface PageContent {
13
- /** The entry's title. Rendered as the `h1` unless a hero already carries one. */
14
- readonly title: string;
15
- readonly blocks: readonly VocabularyBlock[];
16
- }
17
- /**
18
- * A page has exactly one `h1`.
19
- *
20
- * A `hero` declares `headingLevel: 'h1'` and renders the title itself, so the
21
- * layout must not render a second one; without a hero, nothing else on the page
22
- * would — `prose` starts at `h2` — and the page would have no `h1` at all.
23
- */
24
- export declare function pageHasOwnHeading(blocks: readonly VocabularyBlock[]): boolean;
25
- export declare function renderPage(page: PageContent, ctx: RenderContext, entries?: FetchedEntries): HtmlElement;
11
+ export type { FetchedEntries, PageContent };
12
+ export { pageHasOwnHeading, renderEntryHeader, withBlockKey };
13
+ export declare function renderBlock(block: VocabularyBlock, ctx: RenderContext, entries?: FetchedEntries, registry?: BlockRegistry): HtmlElement | null;
14
+ export declare function renderPage(page: PageContent, ctx: RenderContext, entries?: FetchedEntries, registry?: BlockRegistry): HtmlElement;
26
15
  //# sourceMappingURL=render-block.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"render-block.d.ts","sourceRoot":"","sources":["../../../src/render/render-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAavE,OAAO,EAAE,KAAK,WAAW,EAAK,MAAM,WAAW,CAAA;AAE/C;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC,CAAA;AAE9E,wBAAgB,WAAW,CACzB,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,GAC3B,WAAW,GAAG,IAAI,CAsCpB;AAED,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;CAC5C;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAE7E;AAmCD,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,GAC3B,WAAW,CAOb"}
1
+ {"version":3,"file":"render-block.d.ts","sourceRoot":"","sources":["../../../src/render/render-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAoB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC5F,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,iBAAiB,EACjB,iBAAiB,EAEjB,YAAY,EAEb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAkBzD,OAAO,EAAE,KAAK,WAAW,EAAK,MAAM,WAAW,CAAA;AAE/C;;;;;GAKG;AACH,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,CAAA;AAC3C,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAA;AAE7D,wBAAgB,WAAW,CACzB,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,EAC5B,QAAQ,CAAC,EAAE,aAAa,GACvB,WAAW,GAAG,IAAI,CAcpB;AA0DD,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,EAC5B,QAAQ,CAAC,EAAE,aAAa,GACvB,WAAW,CAkBb"}
@@ -1,3 +1,6 @@
1
+ import { VOCABULARY_NAMES } from '@cogenta/blocks';
2
+ import { pageHasOwnHeading, renderEntryHeader, resolveBlockForRender, withBlockKey, withBlockVariant, } from '@cogenta/theme-kit';
3
+ import { renderAccordion } from './blocks/accordion.js';
1
4
  import { renderCollectionList } from './blocks/collection-list.js';
2
5
  import { renderCta } from './blocks/cta.js';
3
6
  import { renderEmbed } from './blocks/embed.js';
@@ -5,95 +8,93 @@ import { renderFaq } from './blocks/faq.js';
5
8
  import { renderFeatureGrid } from './blocks/feature-grid.js';
6
9
  import { renderGallery } from './blocks/gallery.js';
7
10
  import { renderHero } from './blocks/hero.js';
11
+ import { renderLogoStrip } from './blocks/logo-strip.js';
8
12
  import { renderLogos } from './blocks/logos.js';
9
13
  import { renderMediaFigure } from './blocks/media-figure.js';
14
+ import { renderPricingTable } from './blocks/pricing-table.js';
10
15
  import { renderProse } from './blocks/prose.js';
11
16
  import { renderQuote } from './blocks/quote.js';
17
+ import { renderStatCounter } from './blocks/stat-counter.js';
12
18
  import { renderStats } from './blocks/stats.js';
19
+ import { renderTestimonial } from './blocks/testimonial.js';
13
20
  import { h } from './html.js';
14
- export function renderBlock(block, ctx, entries = {}) {
15
- switch (block._type) {
21
+ export { pageHasOwnHeading, renderEntryHeader, withBlockKey };
22
+ export function renderBlock(block, ctx, entries = {}, registry) {
23
+ // `block`'s type says `VocabularyBlock`, but the value crossing this
24
+ // boundary from stored content is not always literally one of the twelve —
25
+ // `theme-render.ts` cannot know at compile time what a block zone holds.
26
+ // Resolving here, once, is what turns an unimplemented theme-private block
27
+ // into its declared fallback instead of a silently blank slot.
28
+ const resolved = resolveBlockForRender(block, VOCABULARY_NAMES, registry);
29
+ if (resolved === null)
30
+ return null;
31
+ const known = resolved;
32
+ // `withBlockVariant` (blocks@2.0, RFC 0002) is applied once here, after
33
+ // dispatch, rather than inside each of the seventeen block renderers —
34
+ // `variant` is envelope data every block carries identically, exactly the
35
+ // same reasoning `withBlockKey` in `renderPage` already follows for `_key`.
36
+ return withBlockVariant(renderKnownBlock(known, ctx, entries), known.variant);
37
+ }
38
+ function renderKnownBlock(known, ctx, entries) {
39
+ switch (known._type) {
16
40
  case 'hero':
17
- return renderHero(block, ctx);
41
+ return renderHero(known, ctx);
18
42
  case 'prose':
19
- return renderProse(block, ctx);
43
+ return renderProse(known, ctx);
20
44
  case 'mediaFigure':
21
- return renderMediaFigure(block, ctx);
45
+ return renderMediaFigure(known, ctx);
22
46
  case 'featureGrid':
23
- return renderFeatureGrid(block, ctx);
47
+ return renderFeatureGrid(known, ctx);
24
48
  case 'cta':
25
- return renderCta(block, ctx);
49
+ return renderCta(known, ctx);
26
50
  case 'gallery':
27
- return renderGallery(block, ctx);
51
+ return renderGallery(known, ctx);
28
52
  case 'quote':
29
- return renderQuote(block, ctx);
53
+ return renderQuote(known, ctx);
30
54
  case 'faq':
31
- return renderFaq(block, ctx);
55
+ return renderFaq(known, ctx);
32
56
  case 'stats':
33
- return renderStats(block, ctx);
57
+ return renderStats(known, ctx);
34
58
  case 'logos':
35
- return renderLogos(block, ctx);
59
+ return renderLogos(known, ctx);
36
60
  case 'collectionList':
37
- return renderCollectionList(block, ctx, entries[block._key] ?? []);
61
+ return renderCollectionList(known, ctx, entries[known._key] ?? []);
38
62
  case 'embed':
39
- return renderEmbed(block, ctx);
63
+ return renderEmbed(known, ctx);
64
+ case 'testimonial':
65
+ return renderTestimonial(known, ctx);
66
+ case 'pricingTable':
67
+ return renderPricingTable(known, ctx);
68
+ case 'accordion':
69
+ return renderAccordion(known, ctx);
70
+ case 'statCounter':
71
+ return renderStatCounter(known, ctx);
72
+ case 'logoStrip':
73
+ return renderLogoStrip(known, ctx);
40
74
  default: {
41
- // Exhaustive over contract B's twelve: `block` is `never` here, so a
42
- // thirteenth block stops this package compiling until it is implemented.
75
+ // Exhaustive over contract B's vocabulary: `known` is `never` here, so a
76
+ // block this package does not implement stops it compiling until it is
77
+ // — every case above is either implemented directly, or the value was
78
+ // already resolved to something that is by `resolveBlockForRender`.
43
79
  // Returning null rather than throwing is deliberate — a theme has no
44
80
  // access to `@cogenta/core`'s error types (contract D refuses the import),
45
81
  // and choosing a fallback block is the render layer's job, not the
46
82
  // theme's.
47
- const unreachable = block;
83
+ const unreachable = known;
48
84
  void unreachable;
49
85
  return null;
50
86
  }
51
87
  }
52
88
  }
53
- /**
54
- * A page has exactly one `h1`.
55
- *
56
- * A `hero` declares `headingLevel: 'h1'` and renders the title itself, so the
57
- * layout must not render a second one; without a hero, nothing else on the page
58
- * would `prose` starts at `h2` and the page would have no `h1` at all.
59
- */
60
- export function pageHasOwnHeading(blocks) {
61
- return blocks.some((block) => block._type === 'hero');
62
- }
63
- /**
64
- * Stamps the block's own `_key` onto the element it rendered to.
65
- *
66
- * The key is contract B's identity for a placed block — minted once, surviving
67
- * reorder, translation and version restore — so it is the one honest way for a
68
- * *reader* of the finished HTML to say "this piece of the page came from that
69
- * block". The visual page builder (L16) is such a reader: it shows the real
70
- * server-rendered page in an iframe and needs to map a clicked element back to
71
- * the block that produced it.
72
- *
73
- * Emitted on every render, never only in a builder mode. A preview that is
74
- * assembled differently from the published page is exactly the divergence the
75
- * builder exists to rule out — one render path, one output, and the fidelity
76
- * test can then assert byte equality rather than "close enough".
77
- *
78
- * It stays a data attribute and it stays out of the block renderers: no block
79
- * has to remember it, and nothing about layout or styling depends on it.
80
- *
81
- * Its companion is `data-field`, written by the block renderers themselves on
82
- * the single element that carries one plain-text field's whole value —
83
- * `hero`'s title, `quote`'s author, and so on. A field only earns the
84
- * attribute when it already had an element of its own: none of them changed
85
- * shape to get it, so the outline, the styling and the snapshots are the same
86
- * page they were, with one more attribute on some elements. Rich text and
87
- * repeated list items carry none, which is the honest answer — a builder
88
- * cannot edit them in place from a text node, and pretending otherwise would
89
- * be the divergence all of this exists to avoid.
90
- */
91
- function withBlockKey(element, key) {
92
- if (element === null)
93
- return null;
94
- return { ...element, attrs: { ...element.attrs, 'data-block-key': key } };
95
- }
96
- export function renderPage(page, ctx, entries = {}) {
97
- return h('main', { class: 'cg-main', id: 'cg-main' }, pageHasOwnHeading(page.blocks) ? null : h('h1', { class: 'cg-page__title' }, page.title), page.blocks.map((block) => withBlockKey(renderBlock(block, ctx, entries), block._key)));
89
+ export function renderPage(page, ctx, entries = {}, registry) {
90
+ // `theme@1.4` (L25 D2): `renderEntryHeader` already returns `null` for a
91
+ // page with no `entry` meta *and* for one whose blocks already draw their
92
+ // own heading (a `hero`), so the bare `<h1 class="cg-page__title">`
93
+ // fallback below is the right markup in both of those cases and only
94
+ // thosenever a double heading, and never a page with none at all.
95
+ const entryHeader = renderEntryHeader(page, ctx);
96
+ return h('main', { class: 'cg-main', id: 'cg-main' }, entryHeader, entryHeader === null && !pageHasOwnHeading(page.blocks)
97
+ ? h('h1', { class: 'cg-page__title' }, page.title)
98
+ : null, page.blocks.map((block) => withBlockKey(renderBlock(block, ctx, entries, registry), block._key)));
98
99
  }
99
100
  //# sourceMappingURL=render-block.js.map