@cogenta/theme-docs 0.3.2

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 (117) hide show
  1. package/LICENSE +373 -0
  2. package/dist/src/index.d.ts +21 -0
  3. package/dist/src/index.d.ts.map +1 -0
  4. package/dist/src/index.js +21 -0
  5. package/dist/src/index.js.map +1 -0
  6. package/dist/src/render/blocks/accordion.d.ts +4 -0
  7. package/dist/src/render/blocks/accordion.d.ts.map +1 -0
  8. package/dist/src/render/blocks/accordion.js +15 -0
  9. package/dist/src/render/blocks/accordion.js.map +1 -0
  10. package/dist/src/render/blocks/collection-list.d.ts +14 -0
  11. package/dist/src/render/blocks/collection-list.d.ts.map +1 -0
  12. package/dist/src/render/blocks/collection-list.js +77 -0
  13. package/dist/src/render/blocks/collection-list.js.map +1 -0
  14. package/dist/src/render/blocks/cta.d.ts +4 -0
  15. package/dist/src/render/blocks/cta.d.ts.map +1 -0
  16. package/dist/src/render/blocks/cta.js +7 -0
  17. package/dist/src/render/blocks/cta.js.map +1 -0
  18. package/dist/src/render/blocks/embed.d.ts +4 -0
  19. package/dist/src/render/blocks/embed.d.ts.map +1 -0
  20. package/dist/src/render/blocks/embed.js +71 -0
  21. package/dist/src/render/blocks/embed.js.map +1 -0
  22. package/dist/src/render/blocks/faq.d.ts +4 -0
  23. package/dist/src/render/blocks/faq.d.ts.map +1 -0
  24. package/dist/src/render/blocks/faq.js +15 -0
  25. package/dist/src/render/blocks/faq.js.map +1 -0
  26. package/dist/src/render/blocks/feature-grid.d.ts +4 -0
  27. package/dist/src/render/blocks/feature-grid.d.ts.map +1 -0
  28. package/dist/src/render/blocks/feature-grid.js +27 -0
  29. package/dist/src/render/blocks/feature-grid.js.map +1 -0
  30. package/dist/src/render/blocks/gallery.d.ts +10 -0
  31. package/dist/src/render/blocks/gallery.d.ts.map +1 -0
  32. package/dist/src/render/blocks/gallery.js +19 -0
  33. package/dist/src/render/blocks/gallery.js.map +1 -0
  34. package/dist/src/render/blocks/hero.d.ts +16 -0
  35. package/dist/src/render/blocks/hero.d.ts.map +1 -0
  36. package/dist/src/render/blocks/hero.js +28 -0
  37. package/dist/src/render/blocks/hero.js.map +1 -0
  38. package/dist/src/render/blocks/logo-strip.d.ts +4 -0
  39. package/dist/src/render/blocks/logo-strip.d.ts.map +1 -0
  40. package/dist/src/render/blocks/logo-strip.js +16 -0
  41. package/dist/src/render/blocks/logo-strip.js.map +1 -0
  42. package/dist/src/render/blocks/logos.d.ts +4 -0
  43. package/dist/src/render/blocks/logos.d.ts.map +1 -0
  44. package/dist/src/render/blocks/logos.js +22 -0
  45. package/dist/src/render/blocks/logos.js.map +1 -0
  46. package/dist/src/render/blocks/media-figure.d.ts +10 -0
  47. package/dist/src/render/blocks/media-figure.d.ts.map +1 -0
  48. package/dist/src/render/blocks/media-figure.js +25 -0
  49. package/dist/src/render/blocks/media-figure.js.map +1 -0
  50. package/dist/src/render/blocks/pricing-table.d.ts +4 -0
  51. package/dist/src/render/blocks/pricing-table.d.ts.map +1 -0
  52. package/dist/src/render/blocks/pricing-table.js +28 -0
  53. package/dist/src/render/blocks/pricing-table.js.map +1 -0
  54. package/dist/src/render/blocks/prose.d.ts +4 -0
  55. package/dist/src/render/blocks/prose.d.ts.map +1 -0
  56. package/dist/src/render/blocks/prose.js +36 -0
  57. package/dist/src/render/blocks/prose.js.map +1 -0
  58. package/dist/src/render/blocks/quote.d.ts +9 -0
  59. package/dist/src/render/blocks/quote.d.ts.map +1 -0
  60. package/dist/src/render/blocks/quote.js +22 -0
  61. package/dist/src/render/blocks/quote.js.map +1 -0
  62. package/dist/src/render/blocks/stat-counter.d.ts +4 -0
  63. package/dist/src/render/blocks/stat-counter.d.ts.map +1 -0
  64. package/dist/src/render/blocks/stat-counter.js +15 -0
  65. package/dist/src/render/blocks/stat-counter.js.map +1 -0
  66. package/dist/src/render/blocks/stats.d.ts +4 -0
  67. package/dist/src/render/blocks/stats.d.ts.map +1 -0
  68. package/dist/src/render/blocks/stats.js +11 -0
  69. package/dist/src/render/blocks/stats.js.map +1 -0
  70. package/dist/src/render/blocks/testimonial.d.ts +11 -0
  71. package/dist/src/render/blocks/testimonial.d.ts.map +1 -0
  72. package/dist/src/render/blocks/testimonial.js +20 -0
  73. package/dist/src/render/blocks/testimonial.js.map +1 -0
  74. package/dist/src/render/chrome.d.ts +3 -0
  75. package/dist/src/render/chrome.d.ts.map +1 -0
  76. package/dist/src/render/chrome.js +94 -0
  77. package/dist/src/render/chrome.js.map +1 -0
  78. package/dist/src/render/render-block.d.ts +15 -0
  79. package/dist/src/render/render-block.d.ts.map +1 -0
  80. package/dist/src/render/render-block.js +176 -0
  81. package/dist/src/render/render-block.js.map +1 -0
  82. package/dist/src/render/term-archive.d.ts +10 -0
  83. package/dist/src/render/term-archive.d.ts.map +1 -0
  84. package/dist/src/render/term-archive.js +32 -0
  85. package/dist/src/render/term-archive.js.map +1 -0
  86. package/dist/theme.config.d.ts +16 -0
  87. package/dist/theme.config.d.ts.map +1 -0
  88. package/dist/theme.config.js +46 -0
  89. package/dist/theme.config.js.map +1 -0
  90. package/package.json +57 -0
  91. package/src/index.ts +20 -0
  92. package/src/render/blocks/accordion.ts +51 -0
  93. package/src/render/blocks/collection-list.ts +170 -0
  94. package/src/render/blocks/cta.ts +25 -0
  95. package/src/render/blocks/embed.ts +94 -0
  96. package/src/render/blocks/faq.ts +46 -0
  97. package/src/render/blocks/feature-grid.ts +67 -0
  98. package/src/render/blocks/gallery.ts +39 -0
  99. package/src/render/blocks/hero.ts +61 -0
  100. package/src/render/blocks/logo-strip.ts +31 -0
  101. package/src/render/blocks/logos.ts +52 -0
  102. package/src/render/blocks/media-figure.ts +36 -0
  103. package/src/render/blocks/pricing-table.ts +72 -0
  104. package/src/render/blocks/prose.ts +49 -0
  105. package/src/render/blocks/quote.ts +35 -0
  106. package/src/render/blocks/stat-counter.ts +37 -0
  107. package/src/render/blocks/stats.ts +38 -0
  108. package/src/render/blocks/testimonial.ts +36 -0
  109. package/src/render/chrome.ts +124 -0
  110. package/src/render/render-block.ts +305 -0
  111. package/src/render/term-archive.ts +78 -0
  112. package/src/styles/archive.css +39 -0
  113. package/src/styles/base.css +1106 -0
  114. package/src/styles/blocks.css +1238 -0
  115. package/src/styles/theme.css +34 -0
  116. package/src/styles/tokens.css +307 -0
  117. package/tokens.json +36 -0
@@ -0,0 +1,20 @@
1
+ import { h, image, renderRichText } from '@cogenta/theme-kit';
2
+ /**
3
+ * `blocks@2.0` (RFC 0001). The same `<figure><blockquote>…</blockquote>
4
+ * <figcaption>` pattern `quote` uses, kept consistent so the two read as
5
+ * siblings — the quote itself is rich text here, and the attribution is
6
+ * the block's single grouped `attribution` field rather than three loose
7
+ * ones.
8
+ */
9
+ export function renderTestimonial(block, ctx) {
10
+ const { attribution } = block;
11
+ return h('figure', { class: 'cg-block cg-testimonial', 'data-block': 'testimonial' }, h('blockquote', { class: 'cg-testimonial__quote' }, renderRichText(ctx, block.quote)), h('figcaption', { class: 'cg-testimonial__attribution' }, attribution.avatar === undefined
12
+ ? null
13
+ : image(ctx, attribution.avatar, {
14
+ className: 'cg-testimonial__avatar',
15
+ variant: { width: 96, height: 96, fit: 'cover' },
16
+ }), h('span', { class: 'cg-testimonial__who' }, h('span', { class: 'cg-testimonial__name' }, attribution.name), attribution.role === undefined
17
+ ? null
18
+ : h('span', { class: 'cg-testimonial__role' }, attribution.role))));
19
+ }
20
+ //# sourceMappingURL=testimonial.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testimonial.js","sourceRoot":"","sources":["../../../../src/render/blocks/testimonial.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,CAAC,EAAE,KAAK,EAAsB,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnG;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAuB,EAAE,GAAkB;IAC3E,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAA;IAC7B,OAAO,CAAC,CACN,QAAQ,EACR,EAAE,KAAK,EAAE,yBAAyB,EAAE,YAAY,EAAE,aAAa,EAAE,EACjE,CAAC,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EACrF,CAAC,CACC,YAAY,EACZ,EAAE,KAAK,EAAE,6BAA6B,EAAE,EACxC,WAAW,CAAC,MAAM,KAAK,SAAS;QAC9B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,WAAW,CAAC,MAAM,EAAE;YAC7B,SAAS,EAAE,wBAAwB;YACnC,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;SACjD,CAAC,EACN,CAAC,CACC,MAAM,EACN,EAAE,KAAK,EAAE,qBAAqB,EAAE,EAChC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,EAC9D,WAAW,CAAC,IAAI,KAAK,SAAS;QAC5B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,CACnE,CACF,CACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type ChromeInput, type ChromeResult } from '@cogenta/theme-kit';
2
+ export declare function renderChrome(input: ChromeInput): ChromeResult;
3
+ //# sourceMappingURL=chrome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../../src/render/chrome.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,YAAY,EAOlB,MAAM,oBAAoB,CAAA;AA0D3B,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAuD7D"}
@@ -0,0 +1,94 @@
1
+ import { escapeAttribute, escapeText, renderBrandMark, renderSocialLinks, renderThemeToggle, serialize, } from '@cogenta/theme-kit';
2
+ /**
3
+ * This theme's own header and footer — structurally distinct from the
4
+ * canonical theme's, not a recolour of it: a docs site's header carries a
5
+ * genuine CSS-only mobile menu (a `<details>` disclosure, never a script),
6
+ * because "Docs / Guides / Reference / Blog" plus a header action does not
7
+ * fit a narrow viewport the way three links do.
8
+ *
9
+ * The mobile panel is a **second, hidden-by-default copy** of the same nav
10
+ * markup, not a repositioned single copy: two static layouts (`display:none`
11
+ * either way at a given viewport width) is the only zero-JS way to put the
12
+ * links inline on a wide screen and inside a disclosure on a narrow one.
13
+ * `display:none` removes the inactive copy from the accessibility tree, so a
14
+ * screen reader is never offered two "Primary" navigations at once — only
15
+ * the sighted, CSS-driven layout differs.
16
+ *
17
+ * Footer: brand column (name + tagline), a footer nav column, social links,
18
+ * a short "about" note, and Cogenta's own credit (or its white-label
19
+ * replacement) — `brandingHtml` placed exactly once, unaltered.
20
+ */
21
+ function navItems(links) {
22
+ return links
23
+ .filter((link) => link.href !== null || link.kind === 'submenu-placeholder')
24
+ .map((link) => {
25
+ const label = escapeText(link.label);
26
+ const titleAttr = link.title === null ? '' : ` title="${escapeAttribute(link.title)}"`;
27
+ if (link.href === null)
28
+ return `<li><span${titleAttr}>${label}</span></li>`;
29
+ const href = escapeAttribute(link.href);
30
+ const target = link.openInNewTab ? ' target="_blank" rel="noopener"' : '';
31
+ return `<li><a href="${href}"${target}${titleAttr}>${label}</a></li>`;
32
+ })
33
+ .join('');
34
+ }
35
+ function renderNav(links, className, label) {
36
+ const items = navItems(links);
37
+ return items === ''
38
+ ? ''
39
+ : `<nav class="${className}" aria-label="${label}"><ul class="cg-menu">${items}</ul></nav>`;
40
+ }
41
+ /** The header's own call-to-action link (`theme@1.4`), reusing `.cg-action`'s own look. */
42
+ function renderHeaderAction(action, className) {
43
+ if (action === undefined)
44
+ return '';
45
+ return (`<a class="cg-action ${className}" data-emphasis="primary" ` +
46
+ `href="${escapeAttribute(action.href)}">${escapeText(action.label)}</a>`);
47
+ }
48
+ /** Three bars, drawn once for this file — not part of `renderIcon`'s closed vocabulary, since a "menu" glyph names no contract B field. */
49
+ const HAMBURGER_SVG = '<svg class="cg-nav-toggle__icon" viewBox="0 0 24 24" width="22" height="22" fill="none" ' +
50
+ 'stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false">' +
51
+ '<path d="M4 6h16M4 12h16M4 18h16"/></svg>';
52
+ export function renderChrome(input) {
53
+ const siteName = escapeAttribute(input.site.name);
54
+ const siteNameText = escapeText(input.site.name);
55
+ const mark = renderBrandMark(input.brand, { className: 'cg-site-header__logo' }) ?? siteNameText;
56
+ const desktopNav = renderNav(input.headerNav, 'cg-site-header__nav', 'Primary');
57
+ const themeToggle = serialize(renderThemeToggle(input.locale, { className: 'cg-theme-toggle' }));
58
+ const desktopAction = renderHeaderAction(input.headerAction, 'cg-site-header__action');
59
+ const mobileNavItems = navItems(input.headerNav);
60
+ const mobileAction = renderHeaderAction(input.headerAction, 'cg-nav-toggle__action');
61
+ const mobilePanel = mobileNavItems === '' && mobileAction === ''
62
+ ? ''
63
+ : `<nav class="cg-nav-toggle__panel" aria-label="Primary">` +
64
+ `${mobileNavItems === '' ? '' : `<ul class="cg-menu">${mobileNavItems}</ul>`}` +
65
+ `${mobileAction}</nav>`;
66
+ const toggle = mobilePanel === ''
67
+ ? ''
68
+ : `<details class="cg-nav-toggle"><summary class="cg-nav-toggle__button" aria-label="Menu">${HAMBURGER_SVG}</summary>${mobilePanel}</details>`;
69
+ const header = `<header class="cg-site-header"><div class="cg-site-header__inner">` +
70
+ `<a class="cg-site-header__home" href="${escapeAttribute(input.homeHref)}">${mark}</a>` +
71
+ `${desktopNav}${themeToggle}${desktopAction}${toggle}` +
72
+ `</div></header>`;
73
+ const footerNav = renderNav(input.footerNav, 'cg-site-footer__nav', 'Footer');
74
+ const tagline = input.tagline === undefined
75
+ ? ''
76
+ : `<p class="cg-site-footer__tagline">${escapeText(input.tagline)}</p>`;
77
+ const socialElement = input.social === undefined
78
+ ? null
79
+ : renderSocialLinks(input.social, {
80
+ className: 'cg-site-footer__social',
81
+ itemClassName: 'cg-site-footer__social-item',
82
+ });
83
+ const social = socialElement === null ? '' : serialize(socialElement);
84
+ const footerNote = input.footerNote === undefined
85
+ ? ''
86
+ : `<p class="cg-site-footer__note">${escapeText(input.footerNote)}</p>`;
87
+ const footer = `<footer class="cg-site-footer"><div class="cg-site-footer__grid">` +
88
+ `<div class="cg-site-footer__brand"><a href="${escapeAttribute(input.homeHref)}">${siteName}</a>${tagline}${social}</div>` +
89
+ `<div class="cg-site-footer__nav-col">${footerNav}</div>` +
90
+ `<div class="cg-site-footer__about-col">${footerNote}<div class="cg-site-footer__branding">${input.brandingHtml}</div></div>` +
91
+ `</div><div class="cg-site-footer__bottom"><span>${siteName}</span></div></footer>`;
92
+ return { header, footer };
93
+ }
94
+ //# sourceMappingURL=chrome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../../src/render/chrome.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type BlockRegistry, type VocabularyBlock } from '@cogenta/blocks';
2
+ import { type FetchedEntries, type HtmlElement, type PageContent, type RenderContext } from '@cogenta/theme-kit';
3
+ export type { FetchedEntries, PageContent };
4
+ export declare function renderBlock(block: VocabularyBlock, ctx: RenderContext, entries?: FetchedEntries, registry?: BlockRegistry): HtmlElement | null;
5
+ /**
6
+ * `<main id="cg-main">` is mandatory: it is the skip-link's target, written
7
+ * once by `@cogenta/cli`'s own render path.
8
+ *
9
+ * `withBlockKey` stamps every rendered block with its contract-B `_key`, on
10
+ * every page including a doc page's content column — the visual page
11
+ * builder maps a clicked element back to the block that produced it, for
12
+ * this theme exactly as for every other one.
13
+ */
14
+ export declare function renderPage(page: PageContent, ctx: RenderContext, entries?: FetchedEntries, registry?: BlockRegistry): HtmlElement;
15
+ //# sourceMappingURL=render-block.d.ts.map
@@ -0,0 +1 @@
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,EAIL,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,WAAW,EAEhB,KAAK,aAAa,EAKnB,MAAM,oBAAoB,CAAA;AAmB3B,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,CAAA;AAE3C,wBAAgB,WAAW,CACzB,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,EAC5B,QAAQ,CAAC,EAAE,aAAa,GACvB,WAAW,GAAG,IAAI,CAKpB;AAsOD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,EAC5B,QAAQ,CAAC,EAAE,aAAa,GACvB,WAAW,CAcb"}
@@ -0,0 +1,176 @@
1
+ import { VOCABULARY_NAMES } from '@cogenta/blocks';
2
+ import { entryHref, entryTitle, h, pageHasOwnHeading, renderEntryHeader, resolveBlockForRender, withBlockKey, withBlockVariant, } from '@cogenta/theme-kit';
3
+ import { renderAccordion } from './blocks/accordion.js';
4
+ import { renderCollectionList } from './blocks/collection-list.js';
5
+ import { renderCta } from './blocks/cta.js';
6
+ import { renderEmbed } from './blocks/embed.js';
7
+ import { renderFaq } from './blocks/faq.js';
8
+ import { renderFeatureGrid } from './blocks/feature-grid.js';
9
+ import { renderGallery } from './blocks/gallery.js';
10
+ import { renderHero } from './blocks/hero.js';
11
+ import { renderLogoStrip } from './blocks/logo-strip.js';
12
+ import { renderLogos } from './blocks/logos.js';
13
+ import { renderMediaFigure } from './blocks/media-figure.js';
14
+ import { renderPricingTable } from './blocks/pricing-table.js';
15
+ import { renderProse } from './blocks/prose.js';
16
+ import { renderQuote } from './blocks/quote.js';
17
+ import { renderStatCounter } from './blocks/stat-counter.js';
18
+ import { renderStats } from './blocks/stats.js';
19
+ import { renderTestimonial } from './blocks/testimonial.js';
20
+ export function renderBlock(block, ctx, entries = {}, registry) {
21
+ const resolved = resolveBlockForRender(block, VOCABULARY_NAMES, registry);
22
+ if (resolved === null)
23
+ return null;
24
+ const known = resolved;
25
+ return withBlockVariant(renderKnownBlock(known, ctx, entries), known.variant);
26
+ }
27
+ function renderKnownBlock(known, ctx, entries) {
28
+ switch (known._type) {
29
+ case 'hero':
30
+ return renderHero(known, ctx);
31
+ case 'prose':
32
+ return renderProse(known, ctx);
33
+ case 'mediaFigure':
34
+ return renderMediaFigure(known, ctx);
35
+ case 'featureGrid':
36
+ return renderFeatureGrid(known, ctx);
37
+ case 'cta':
38
+ return renderCta(known, ctx);
39
+ case 'gallery':
40
+ return renderGallery(known, ctx);
41
+ case 'quote':
42
+ return renderQuote(known, ctx);
43
+ case 'faq':
44
+ return renderFaq(known, ctx);
45
+ case 'stats':
46
+ return renderStats(known, ctx);
47
+ case 'logos':
48
+ return renderLogos(known, ctx);
49
+ case 'collectionList':
50
+ return renderCollectionList(known, ctx, entries[known._key] ?? []);
51
+ case 'embed':
52
+ return renderEmbed(known, ctx);
53
+ case 'testimonial':
54
+ return renderTestimonial(known, ctx);
55
+ case 'pricingTable':
56
+ return renderPricingTable(known, ctx);
57
+ case 'accordion':
58
+ return renderAccordion(known, ctx);
59
+ case 'statCounter':
60
+ return renderStatCounter(known, ctx);
61
+ case 'logoStrip':
62
+ return renderLogoStrip(known, ctx);
63
+ default: {
64
+ const unreachable = known;
65
+ void unreachable;
66
+ return null;
67
+ }
68
+ }
69
+ }
70
+ /**
71
+ * The name every doc page's own blueprint-seeded sidebar `collectionList`
72
+ * targets — checked structurally (first block, this collection) rather than
73
+ * by any flag on the block, because contract B carries no "this is chrome,
74
+ * not content" bit and inventing one would be a contract change for a
75
+ * single theme's layout choice.
76
+ */
77
+ const DOC_PAGE_COLLECTION = 'doc_page';
78
+ function isDocSidebarBlock(block) {
79
+ return block._type === 'collectionList' && block.collection === DOC_PAGE_COLLECTION;
80
+ }
81
+ /** The sidebar entry whose own link resolves to the page being rendered — the "current page" the brief asks the sidebar to highlight and the breadcrumb to name. */
82
+ function findCurrentEntry(entries, ctx) {
83
+ return entries.find((entry) => entryHref(entry, ctx) === ctx.url.pathname);
84
+ }
85
+ /**
86
+ * The doc-page sidebar — grouped by each entry's own `section` field, in the
87
+ * order the entries were fetched (the blueprint seeds them in `order`
88
+ * within a section already; `collectionList.sort` cannot name `section`/
89
+ * `order`, so an editor who reorders sections relies on the fetch order,
90
+ * exactly like the "All guides" index on the home page does).
91
+ */
92
+ function renderSidebarPanel(entries, ctx, currentHref) {
93
+ const groups = new Map();
94
+ for (const entry of entries) {
95
+ const section = typeof entry.section === 'string' && entry.section !== ''
96
+ ? entry.section
97
+ : ctx.t('entry.untitled');
98
+ const list = groups.get(section) ?? [];
99
+ list.push(entry);
100
+ groups.set(section, list);
101
+ }
102
+ return h('nav', { class: 'cg-docs__nav-panel', 'aria-label': 'Documentation' }, [...groups.entries()].map(([section, sectionEntries]) => h('div', { class: 'cg-docs__nav-group' }, h('p', { class: 'cg-docs__nav-heading' }, section), h('ul', { class: 'cg-docs__nav-items' }, sectionEntries.map((entry) => {
103
+ const href = entryHref(entry, ctx);
104
+ const isCurrent = href === currentHref;
105
+ return h('li', {}, h('a', {
106
+ class: 'cg-docs__nav-link',
107
+ href,
108
+ 'aria-current': isCurrent ? 'page' : undefined,
109
+ }, entryTitle(entry, ctx)));
110
+ })))));
111
+ }
112
+ /**
113
+ * The sidebar, in two copies — the same zero-JS technique `chrome.ts` already
114
+ * uses for the header's own mobile menu, and for the same reason: Chrome (and
115
+ * every other engine implementing the current HTML rendering rules) hides a
116
+ * closed `<details>`'s non-summary content through its own internal
117
+ * `::details-content` box, not through the plain CSS `display: none` the spec
118
+ * text describes — so a stylesheet rule that sets `display: block` on that
119
+ * content, however specific, does not reliably bring it back while the
120
+ * element itself stays closed. Verified live: a build with a single
121
+ * `<details>` forced open only above the two-column breakpoint rendered an
122
+ * empty sidebar column at 1280px in a real Chrome tab, despite every
123
+ * computed style reporting `display: block`.
124
+ *
125
+ * The fix is the same one already proven for the header: a plain, always-
126
+ * live `<nav>` for the desktop column (nothing to collapse, so nothing for
127
+ * the browser to hide), and a **separate** `<details>` disclosure — a full
128
+ * second copy of the same panel — for narrow viewports. Exactly one of the
129
+ * two is ever `display: block` at a given viewport width (`base.css`), so a
130
+ * screen reader is never offered two "Documentation" navigations at once,
131
+ * matching the header's own accessibility guarantee.
132
+ */
133
+ function renderSidebar(entries, ctx, currentHref) {
134
+ return h('div', { class: 'cg-docs__nav-desktop' }, renderSidebarPanel(entries, ctx, currentHref));
135
+ }
136
+ function renderSidebarMobile(entries, ctx, currentHref) {
137
+ return h('details', { class: 'cg-docs__nav-mobile' }, h('summary', { class: 'cg-docs__nav-toggle' }, 'On this site'), renderSidebarPanel(entries, ctx, currentHref));
138
+ }
139
+ function renderBreadcrumb(section, title) {
140
+ return h('nav', { class: 'cg-docs__breadcrumb', 'aria-label': 'Breadcrumb' }, h('ol', {}, section === undefined ? null : h('li', {}, section), h('li', { 'aria-current': 'page' }, title)));
141
+ }
142
+ /**
143
+ * A doc page: two columns, CSS-only. The sidebar comes from the page's own
144
+ * *first* block — a `collectionList` on `doc_page` the blueprint seeds on
145
+ * every doc page for exactly this purpose — rendered as navigation rather
146
+ * than as a card list, and dropped from the ordinary block stream so it
147
+ * never also appears as content. The remaining blocks render in the content
148
+ * column, unchanged.
149
+ */
150
+ function renderDocPage(page, ctx, sidebarBlock, entries, registry) {
151
+ const sidebarEntries = entries[sidebarBlock._key] ?? [];
152
+ const currentHref = ctx.url.pathname;
153
+ const current = findCurrentEntry(sidebarEntries, ctx);
154
+ const section = typeof current?.section === 'string' ? current.section : undefined;
155
+ const contentBlocks = page.blocks.slice(1);
156
+ const hasOwnHeading = pageHasOwnHeading(contentBlocks);
157
+ const entryHeader = renderEntryHeader(page, ctx);
158
+ return h('main', { class: 'cg-main cg-docs', id: 'cg-main' }, withBlockKey(h('div', { class: 'cg-docs__nav' }, renderSidebar(sidebarEntries, ctx, currentHref), renderSidebarMobile(sidebarEntries, ctx, currentHref)), sidebarBlock._key), h('div', { class: 'cg-docs__content' }, renderBreadcrumb(section, page.title), entryHeader ?? (hasOwnHeading ? null : h('h1', { class: 'cg-docs__title' }, page.title)), contentBlocks.map((block) => withBlockKey(renderBlock(block, ctx, entries, registry), block._key))));
159
+ }
160
+ /**
161
+ * `<main id="cg-main">` is mandatory: it is the skip-link's target, written
162
+ * once by `@cogenta/cli`'s own render path.
163
+ *
164
+ * `withBlockKey` stamps every rendered block with its contract-B `_key`, on
165
+ * every page including a doc page's content column — the visual page
166
+ * builder maps a clicked element back to the block that produced it, for
167
+ * this theme exactly as for every other one.
168
+ */
169
+ export function renderPage(page, ctx, entries = {}, registry) {
170
+ const first = page.blocks[0];
171
+ if (first !== undefined && isDocSidebarBlock(first)) {
172
+ return renderDocPage(page, ctx, first, entries, registry);
173
+ }
174
+ 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, registry), block._key)));
175
+ }
176
+ //# sourceMappingURL=render-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-block.js","sourceRoot":"","sources":["../../../src/render/render-block.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type HtmlElement, type TermArchiveInput } from '@cogenta/theme-kit';
2
+ /**
3
+ * The taxonomy-term archive (contract D `theme@1.3`) — a simple titled list,
4
+ * deliberately: a documentation site's own information architecture is the
5
+ * sidebar (`section`/`order`, plain fields), not a taxonomy, so this page is
6
+ * the plain fallback for a term an editor still chooses to classify content
7
+ * under, not a second navigation surface competing with the sidebar.
8
+ */
9
+ export declare function renderTermArchive(input: TermArchiveInput): HtmlElement;
10
+ //# sourceMappingURL=term-archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"term-archive.d.ts","sourceRoot":"","sources":["../../../src/render/term-archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAK,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE/E;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAsDtE"}
@@ -0,0 +1,32 @@
1
+ import { h } from '@cogenta/theme-kit';
2
+ /**
3
+ * The taxonomy-term archive (contract D `theme@1.3`) — a simple titled list,
4
+ * deliberately: a documentation site's own information architecture is the
5
+ * sidebar (`section`/`order`, plain fields), not a taxonomy, so this page is
6
+ * the plain fallback for a term an editor still chooses to classify content
7
+ * under, not a second navigation surface competing with the sidebar.
8
+ */
9
+ export function renderTermArchive(input) {
10
+ const rows = input.entries.map((entry) => h('li', { class: 'cg-list__row' }, h('div', { class: 'cg-list__body' }, h('h2', { class: 'cg-list__title' }, entry.href === null
11
+ ? entry.title
12
+ : h('a', { class: 'cg-list__link', href: entry.href }, entry.title)), entry.summary === null ? null : h('p', { class: 'cg-list__excerpt' }, entry.summary)), entry.publishedAt === null
13
+ ? null
14
+ : h('time', { class: 'cg-list__date', datetime: entry.publishedAt }, entry.publishedAt.slice(0, 10))));
15
+ return h('main', { class: 'cg-main cg-archive', id: 'cg-main' }, input.ancestors.length === 0
16
+ ? null
17
+ : h('nav', { class: 'cg-archive__breadcrumb', 'aria-label': input.labels.breadcrumb }, h('ol', {}, ...input.ancestors.map((l) => h('li', {}, h('a', { href: l.href }, l.label))))), h('h1', { class: 'cg-page__title' }, input.term.label), input.children.length === 0
18
+ ? null
19
+ : h('ul', { class: 'cg-archive__children', 'aria-label': input.labels.subterms }, ...input.children.map((c) => h('li', {}, h('a', { href: c.href }, c.label)))), rows.length === 0
20
+ ? h('p', { class: 'cg-list__empty' }, input.labels.empty)
21
+ : h('ul', { class: 'cg-list__items' }, ...rows), pager(input));
22
+ }
23
+ function pager(input) {
24
+ if (input.page.previousHref === null && input.page.nextHref === null)
25
+ return null;
26
+ return h('nav', { class: 'cg-archive__pager', 'aria-label': input.labels.pagination }, input.page.previousHref === null
27
+ ? null
28
+ : h('a', { rel: 'prev', href: input.page.previousHref }, input.labels.previous), input.page.nextHref === null
29
+ ? null
30
+ : h('a', { rel: 'next', href: input.page.nextHref }, input.labels.next));
31
+ }
32
+ //# sourceMappingURL=term-archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"term-archive.js","sourceRoot":"","sources":["../../../src/render/term-archive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Contract D — Theme, `theme@1.4`.
3
+ *
4
+ * `implements` lists the seventeen blocks of contract B (`blocks@2.0`, RFC
5
+ * 0001) in the order the contract lists them — see
6
+ * `@cogenta/theme-canonical/theme.config.ts` for why that order matters
7
+ * (installation refuses an incomplete theme).
8
+ *
9
+ * `runtime: 'static'` describes what this theme package itself needs; the
10
+ * one block in the vocabulary that reads at request time (`collectionList`)
11
+ * still declares `runtime: 'server'` on its own, in the vocabulary — that is
12
+ * a property of the block, not of the theme rendering it.
13
+ */
14
+ declare const _default: import("@cogenta/render").ThemeManifest;
15
+ export default _default;
16
+ //# sourceMappingURL=theme.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.config.d.ts","sourceRoot":"","sources":["../theme.config.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,46 @@
1
+ import { defineTheme } from '@cogenta/render';
2
+ /**
3
+ * Contract D — Theme, `theme@1.4`.
4
+ *
5
+ * `implements` lists the seventeen blocks of contract B (`blocks@2.0`, RFC
6
+ * 0001) in the order the contract lists them — see
7
+ * `@cogenta/theme-canonical/theme.config.ts` for why that order matters
8
+ * (installation refuses an incomplete theme).
9
+ *
10
+ * `runtime: 'static'` describes what this theme package itself needs; the
11
+ * one block in the vocabulary that reads at request time (`collectionList`)
12
+ * still declares `runtime: 'server'` on its own, in the vocabulary — that is
13
+ * a property of the block, not of the theme rendering it.
14
+ */
15
+ export default defineTheme({
16
+ name: 'docs',
17
+ version: '1.0.0',
18
+ description: 'A dense, reference-first documentation theme: a sticky sidebar-navigated doc layout, real code blocks, a genuine dark mode.',
19
+ author: 'Cogenta',
20
+ engine: '^1.0.0',
21
+ blocks: '^2.0.0',
22
+ implements: [
23
+ 'hero',
24
+ 'prose',
25
+ 'mediaFigure',
26
+ 'featureGrid',
27
+ 'cta',
28
+ 'gallery',
29
+ 'quote',
30
+ 'faq',
31
+ 'stats',
32
+ 'logos',
33
+ 'collectionList',
34
+ 'embed',
35
+ 'testimonial',
36
+ 'pricingTable',
37
+ 'accordion',
38
+ 'statCounter',
39
+ 'logoStrip',
40
+ ],
41
+ collections: ['doc_page', 'page'],
42
+ runtime: 'static',
43
+ tokens: './tokens.json',
44
+ a11y: { verified: 'WCAG-2.2-AA' },
45
+ });
46
+ //# sourceMappingURL=theme.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.config.js","sourceRoot":"","sources":["../theme.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C;;;;;;;;;;;;GAYG;AACH,eAAe,WAAW,CAAC;IACzB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,OAAO;IAChB,WAAW,EACT,6HAA6H;IAC/H,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE;QACV,MAAM;QACN,OAAO;QACP,aAAa;QACb,aAAa;QACb,KAAK;QACL,SAAS;QACT,OAAO;QACP,KAAK;QACL,OAAO;QACP,OAAO;QACP,gBAAgB;QAChB,OAAO;QACP,aAAa;QACb,cAAc;QACd,WAAW;QACX,aAAa;QACb,WAAW;KACZ;IACD,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;IACjC,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,eAAe;IACvB,IAAI,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE;CAClC,CAAC,CAAA"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@cogenta/theme-docs",
3
+ "version": "0.3.2",
4
+ "description": "A dense, reference-first documentation theme for Cogenta: a sticky sidebar-navigated doc layout, real code blocks, and a genuine dark mode — zero client JavaScript.",
5
+ "license": "MPL-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/src/index.d.ts",
11
+ "default": "./dist/src/index.js"
12
+ },
13
+ "./theme.config": {
14
+ "types": "./dist/theme.config.d.ts",
15
+ "default": "./dist/theme.config.js"
16
+ },
17
+ "./tokens.json": "./tokens.json",
18
+ "./styles/theme.css": "./src/styles/theme.css",
19
+ "./styles/*.css": "./src/styles/*.css"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src",
24
+ "tokens.json"
25
+ ],
26
+ "engines": {
27
+ "node": ">=22.11.0"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "provenance": true
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/cogenta-cms/cogenta.git",
36
+ "directory": "packages/theme-docs"
37
+ },
38
+ "dependencies": {
39
+ "@cogenta/theme-kit": "0.3.2",
40
+ "@cogenta/blocks": "1.0.3",
41
+ "@cogenta/render": "0.2.3"
42
+ },
43
+ "peerDependencies": {
44
+ "astro": "^7.2.1"
45
+ },
46
+ "devDependencies": {
47
+ "astro": "^7.2.1",
48
+ "typescript": "^7.0.2",
49
+ "vitest": "^4.1.10"
50
+ },
51
+ "scripts": {
52
+ "build": "tsc -p tsconfig.json",
53
+ "typecheck": "tsc -p tsconfig.typecheck.json",
54
+ "test": "vitest run --passWithNoTests",
55
+ "test:integration": "vitest run --config vitest.integration.config.ts --passWithNoTests"
56
+ }
57
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ export * from './render/blocks/accordion.js'
2
+ export * from './render/blocks/collection-list.js'
3
+ export * from './render/blocks/cta.js'
4
+ export * from './render/blocks/embed.js'
5
+ export * from './render/blocks/faq.js'
6
+ export * from './render/blocks/feature-grid.js'
7
+ export * from './render/blocks/gallery.js'
8
+ export * from './render/blocks/hero.js'
9
+ export * from './render/blocks/logo-strip.js'
10
+ export * from './render/blocks/logos.js'
11
+ export * from './render/blocks/media-figure.js'
12
+ export * from './render/blocks/pricing-table.js'
13
+ export * from './render/blocks/prose.js'
14
+ export * from './render/blocks/quote.js'
15
+ export * from './render/blocks/stat-counter.js'
16
+ export * from './render/blocks/stats.js'
17
+ export * from './render/blocks/testimonial.js'
18
+ export * from './render/chrome.js'
19
+ export * from './render/render-block.js'
20
+ export * from './render/term-archive.js'
@@ -0,0 +1,51 @@
1
+ import type { AccordionBlock, AccordionItem } from '@cogenta/blocks'
2
+ import {
3
+ blockHeadingTag,
4
+ type HtmlElement,
5
+ h,
6
+ heading,
7
+ type RenderContext,
8
+ renderRichText,
9
+ } from '@cogenta/theme-kit'
10
+
11
+ /**
12
+ * `blocks@2.0` (RFC 0001). Reuses `faq`'s zero-JS `<details>`/`<summary>`
13
+ * mechanics with a markup vocabulary of its own (`cg-panels`, not
14
+ * `cg-faq`), a rotating chevron mark rather than a numbered row.
15
+ */
16
+ function renderItem(item: AccordionItem, ctx: RenderContext): HtmlElement {
17
+ return h(
18
+ 'li',
19
+ { class: 'cg-panels__item' },
20
+ h(
21
+ 'details',
22
+ { class: 'cg-panels__details' },
23
+ h(
24
+ 'summary',
25
+ { class: 'cg-panels__question' },
26
+ h('span', { class: 'cg-panels__question-text' }, item.question),
27
+ h('span', { class: 'cg-panels__chevron', 'aria-hidden': 'true' }),
28
+ ),
29
+ h('div', { class: 'cg-panels__answer' }, renderRichText(ctx, item.answer)),
30
+ ),
31
+ )
32
+ }
33
+
34
+ export function renderAccordion(block: AccordionBlock, ctx: RenderContext): HtmlElement {
35
+ return h(
36
+ 'section',
37
+ { class: 'cg-block cg-panels', 'data-block': 'accordion' },
38
+ block.title === undefined
39
+ ? null
40
+ : heading(
41
+ blockHeadingTag('accordion') ?? 'h2',
42
+ { class: 'cg-panels__title', 'data-field': 'title' },
43
+ block.title,
44
+ ),
45
+ h(
46
+ 'ul',
47
+ { class: 'cg-panels__items' },
48
+ block.items.map((item) => renderItem(item, ctx)),
49
+ ),
50
+ )
51
+ }