@cogenta/theme-magazine 1.1.2 → 1.3.3
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.
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/render/article.d.ts +32 -0
- package/dist/src/render/article.d.ts.map +1 -0
- package/dist/src/render/article.js +137 -0
- package/dist/src/render/article.js.map +1 -0
- package/dist/src/render/blocks/accordion.d.ts.map +1 -1
- package/dist/src/render/blocks/accordion.js +9 -13
- package/dist/src/render/blocks/accordion.js.map +1 -1
- package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
- package/dist/src/render/blocks/collection-list.js +91 -118
- package/dist/src/render/blocks/collection-list.js.map +1 -1
- package/dist/src/render/blocks/cta.d.ts +4 -4
- package/dist/src/render/blocks/cta.d.ts.map +1 -1
- package/dist/src/render/blocks/cta.js +7 -9
- package/dist/src/render/blocks/cta.js.map +1 -1
- package/dist/src/render/blocks/embed.d.ts.map +1 -1
- package/dist/src/render/blocks/embed.js +17 -20
- package/dist/src/render/blocks/embed.js.map +1 -1
- package/dist/src/render/blocks/faq.d.ts.map +1 -1
- package/dist/src/render/blocks/faq.js +12 -11
- package/dist/src/render/blocks/faq.js.map +1 -1
- package/dist/src/render/blocks/feature-grid.d.ts.map +1 -1
- package/dist/src/render/blocks/feature-grid.js +13 -20
- package/dist/src/render/blocks/feature-grid.js.map +1 -1
- package/dist/src/render/blocks/gallery.d.ts +6 -6
- package/dist/src/render/blocks/gallery.d.ts.map +1 -1
- package/dist/src/render/blocks/gallery.js +15 -13
- package/dist/src/render/blocks/gallery.js.map +1 -1
- package/dist/src/render/blocks/hero.d.ts +6 -5
- package/dist/src/render/blocks/hero.d.ts.map +1 -1
- package/dist/src/render/blocks/hero.js +15 -14
- package/dist/src/render/blocks/hero.js.map +1 -1
- package/dist/src/render/blocks/logo-strip.d.ts.map +1 -1
- package/dist/src/render/blocks/logo-strip.js +8 -11
- package/dist/src/render/blocks/logo-strip.js.map +1 -1
- package/dist/src/render/blocks/logos.d.ts.map +1 -1
- package/dist/src/render/blocks/logos.js +16 -16
- package/dist/src/render/blocks/logos.js.map +1 -1
- package/dist/src/render/blocks/media-figure.d.ts +8 -8
- package/dist/src/render/blocks/media-figure.d.ts.map +1 -1
- package/dist/src/render/blocks/media-figure.js +23 -19
- package/dist/src/render/blocks/media-figure.js.map +1 -1
- package/dist/src/render/blocks/pricing-table.d.ts.map +1 -1
- package/dist/src/render/blocks/pricing-table.js +19 -22
- package/dist/src/render/blocks/pricing-table.js.map +1 -1
- package/dist/src/render/blocks/prose.d.ts +6 -10
- package/dist/src/render/blocks/prose.d.ts.map +1 -1
- package/dist/src/render/blocks/prose.js +8 -11
- package/dist/src/render/blocks/prose.js.map +1 -1
- package/dist/src/render/blocks/quote.d.ts +6 -9
- package/dist/src/render/blocks/quote.d.ts.map +1 -1
- package/dist/src/render/blocks/quote.js +11 -13
- package/dist/src/render/blocks/quote.js.map +1 -1
- package/dist/src/render/blocks/stat-counter.d.ts.map +1 -1
- package/dist/src/render/blocks/stat-counter.js +9 -10
- package/dist/src/render/blocks/stat-counter.js.map +1 -1
- package/dist/src/render/blocks/stats.d.ts.map +1 -1
- package/dist/src/render/blocks/stats.js +9 -12
- package/dist/src/render/blocks/stats.js.map +1 -1
- package/dist/src/render/blocks/testimonial.d.ts +4 -13
- package/dist/src/render/blocks/testimonial.d.ts.map +1 -1
- package/dist/src/render/blocks/testimonial.js +7 -15
- package/dist/src/render/blocks/testimonial.js.map +1 -1
- package/dist/src/render/chrome.d.ts.map +1 -1
- package/dist/src/render/chrome.js +109 -97
- package/dist/src/render/chrome.js.map +1 -1
- package/dist/src/render/layout.d.ts +28 -0
- package/dist/src/render/layout.d.ts.map +1 -0
- package/dist/src/render/layout.js +72 -0
- package/dist/src/render/layout.js.map +1 -0
- package/dist/src/render/render-block.d.ts +15 -13
- package/dist/src/render/render-block.d.ts.map +1 -1
- package/dist/src/render/render-block.js +53 -29
- package/dist/src/render/render-block.js.map +1 -1
- package/dist/src/render/story.d.ts +41 -0
- package/dist/src/render/story.d.ts.map +1 -0
- package/dist/src/render/story.js +65 -0
- package/dist/src/render/story.js.map +1 -0
- package/dist/src/render/term-archive.d.ts +0 -10
- package/dist/src/render/term-archive.d.ts.map +1 -1
- package/dist/src/render/term-archive.js +42 -19
- package/dist/src/render/term-archive.js.map +1 -1
- package/dist/src/render/widget-areas.d.ts +12 -0
- package/dist/src/render/widget-areas.d.ts.map +1 -0
- package/dist/src/render/widget-areas.js +19 -0
- package/dist/src/render/widget-areas.js.map +1 -0
- package/dist/theme.config.js +2 -2
- package/dist/theme.config.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +3 -0
- package/src/render/article.ts +239 -0
- package/src/render/blocks/accordion.ts +23 -30
- package/src/render/blocks/collection-list.ts +161 -225
- package/src/render/blocks/cta.ts +19 -13
- package/src/render/blocks/embed.ts +40 -36
- package/src/render/blocks/faq.ts +31 -36
- package/src/render/blocks/feature-grid.ts +26 -36
- package/src/render/blocks/gallery.ts +24 -18
- package/src/render/blocks/hero.ts +32 -32
- package/src/render/blocks/logo-strip.ts +17 -17
- package/src/render/blocks/logos.ts +23 -31
- package/src/render/blocks/media-figure.ts +36 -20
- package/src/render/blocks/pricing-table.ts +29 -34
- package/src/render/blocks/prose.ts +13 -13
- package/src/render/blocks/quote.ts +24 -24
- package/src/render/blocks/stat-counter.ts +16 -24
- package/src/render/blocks/stats.ts +14 -24
- package/src/render/blocks/testimonial.ts +12 -17
- package/src/render/chrome.ts +123 -104
- package/src/render/layout.ts +105 -0
- package/src/render/render-block.ts +61 -33
- package/src/render/story.ts +139 -0
- package/src/render/term-archive.ts +111 -58
- package/src/render/widget-areas.ts +22 -0
- package/src/styles/archive.css +114 -17
- package/src/styles/article.css +237 -0
- package/src/styles/base.css +848 -591
- package/src/styles/blocks.css +903 -921
- package/src/styles/stories.css +593 -0
- package/src/styles/theme.css +28 -9
- package/src/styles/tokens.css +200 -185
- package/src/styles/widgets.css +614 -0
- package/tokens.json +18 -18
|
@@ -1,40 +1,35 @@
|
|
|
1
|
-
import { escapeAttribute, escapeText, renderBrandMark, renderSocialLinks, renderThemeToggle, serialize, } from '@cogenta/theme-kit';
|
|
1
|
+
import { escapeAttribute, escapeText, renderBrandMark, renderFooterWidgets, renderSocialLinks, renderThemeToggle, serialize, } from '@cogenta/theme-kit';
|
|
2
2
|
/**
|
|
3
|
-
* The masthead
|
|
4
|
-
*
|
|
5
|
-
* quiet rubric bar underneath it, the way a print contents strip reads. That
|
|
6
|
-
* is a structurally different header from a left-aligned wordmark plus a
|
|
7
|
-
* right-aligned menu (`theme-canonical`'s own layout): the nameplate gets
|
|
8
|
-
* its own row so it can be set large without competing with the nav for
|
|
9
|
-
* width, and the nav becomes a second, quieter row.
|
|
3
|
+
* The masthead and the colophon (`theme@1.4`), drawn the way a daily draws
|
|
4
|
+
* them.
|
|
10
5
|
*
|
|
11
|
-
*
|
|
12
|
-
* than a static tagline (`Intl.DateTimeFormat(ctx.locale, { dateStyle:
|
|
13
|
-
* 'full' })` on `new Date()` — legitimate here because every page renders
|
|
14
|
-
* per request, `cogenta serve` never caches a rendered page across a day
|
|
15
|
-
* boundary for an anonymous visitor beyond `security.pageMaxAge`, and this
|
|
16
|
-
* theme's own masthead has never claimed to be static-generated — `theme.
|
|
17
|
-
* config.ts` still declares `runtime: 'static'`, which describes what this
|
|
18
|
-
* theme *needs* to render a page, not a promise that today's date is frozen
|
|
19
|
-
* at build time); the rubric row now also carries `headerAction` as a filled
|
|
20
|
-
* "Subscribe"-style button; and a CSS-only `<details>` disclosure collapses
|
|
21
|
-
* the whole rubric row into a hamburger below the nameplate's own
|
|
22
|
-
* breakpoint, exactly the technique `theme-blog`'s masthead already proved
|
|
23
|
-
* against a real browser (a closed `<details>`'s non-summary content cannot
|
|
24
|
-
* be forced open by CSS alone, so the collapsed and expanded nav are two
|
|
25
|
-
* separate `<nav>`s, never one pushed into a state it was never opened
|
|
26
|
-
* into — see that theme's own `chrome.ts` for the verified detail).
|
|
6
|
+
* Masthead, three rows:
|
|
27
7
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
8
|
+
* 1. A thin bar: today's date on the left, the `tagline` in the middle on a
|
|
9
|
+
* wide screen, the `headerAction` and the light/dark control on the right.
|
|
10
|
+
* The action lives here rather than in the navigation so it stays visible
|
|
11
|
+
* on a phone with the menu closed.
|
|
12
|
+
* 2. The nameplate: the site's name in the display face, centred, or its
|
|
13
|
+
* uploaded logo at nameplate scale.
|
|
14
|
+
* 3. The section navigation in spaced capitals between a double rule and a
|
|
15
|
+
* hairline. Below the breakpoint it becomes a panel opened by a CSS-only
|
|
16
|
+
* toggle, a visually hidden checkbox paired with a `<label>`, no
|
|
17
|
+
* `<script>`. The checkbox and label are siblings placed before the
|
|
18
|
+
* `<nav>` so the sibling combinator in `base.css` reaches it.
|
|
19
|
+
*
|
|
20
|
+
* The date is the date the page is rendered, which is what a masthead date
|
|
21
|
+
* means on a site rendered per request.
|
|
22
|
+
*
|
|
23
|
+
* Colophon: the name again on a double rule, then four columns (the tagline
|
|
24
|
+
* and `footerNote`, the footer navigation over two columns, the social
|
|
25
|
+
* profiles with their names), then the legal line: the copyright year and the
|
|
26
|
+
* site's name beside Cogenta's credit (`brandingHtml`, placed once, as
|
|
27
|
+
* received). No column carries a heading: a heading is a word, and a theme
|
|
28
|
+
* has no translation for it. Every `theme@1.4` field renders only when
|
|
29
|
+
* present, so a host that predates them still gets the name and navigation.
|
|
35
30
|
*/
|
|
36
|
-
function
|
|
37
|
-
|
|
31
|
+
function navItems(links) {
|
|
32
|
+
return links
|
|
38
33
|
.filter((link) => link.href !== null || link.kind === 'submenu-placeholder')
|
|
39
34
|
.map((link) => {
|
|
40
35
|
const label = escapeText(link.label);
|
|
@@ -46,88 +41,105 @@ function renderNavItems(links, className) {
|
|
|
46
41
|
return `<li><a href="${href}"${target}${titleAttr}>${label}</a></li>`;
|
|
47
42
|
})
|
|
48
43
|
.join('');
|
|
49
|
-
return items === '' ? '' : `<ul class="${className}">${items}</ul>`;
|
|
50
|
-
}
|
|
51
|
-
/** The rubric row's own call-to-action link (`theme@1.4`) — a filled button, the masthead's one place of solid colour. */
|
|
52
|
-
function renderHeaderAction(action) {
|
|
53
|
-
if (action === undefined)
|
|
54
|
-
return '';
|
|
55
|
-
return (`<a class="cg-action cg-masthead__action" data-emphasis="primary" ` +
|
|
56
|
-
`href="${escapeAttribute(action.href)}">${escapeText(action.label)}</a>`);
|
|
57
44
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return '<span class="cg-masthead__bars" aria-hidden="true"></span>';
|
|
45
|
+
function isoDay(date) {
|
|
46
|
+
return date.toISOString().slice(0, 10);
|
|
61
47
|
}
|
|
62
|
-
function
|
|
48
|
+
function formatToday(date, locale, options) {
|
|
63
49
|
try {
|
|
64
|
-
return new Intl.DateTimeFormat(locale,
|
|
50
|
+
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
65
51
|
}
|
|
66
52
|
catch {
|
|
67
|
-
return new
|
|
53
|
+
return new Intl.DateTimeFormat('en', options).format(date);
|
|
68
54
|
}
|
|
69
55
|
}
|
|
56
|
+
/** `footerNote` as paragraphs: a blank line starts a new one. */
|
|
57
|
+
function renderFooterNote(note) {
|
|
58
|
+
const paragraphs = note
|
|
59
|
+
.replace(/\r\n?/g, '\n')
|
|
60
|
+
.split(/\n\s*\n/)
|
|
61
|
+
.map((paragraph) => paragraph.replace(/\s*\n\s*/g, ' ').trim())
|
|
62
|
+
.filter((paragraph) => paragraph !== '');
|
|
63
|
+
if (paragraphs.length === 0)
|
|
64
|
+
return '';
|
|
65
|
+
return `<div class="cg-colophon__note">${paragraphs
|
|
66
|
+
.map((paragraph) => `<p>${escapeText(paragraph)}</p>`)
|
|
67
|
+
.join('')}</div>`;
|
|
68
|
+
}
|
|
70
69
|
export function renderChrome(input) {
|
|
71
70
|
const siteNameText = escapeText(input.site.name);
|
|
72
|
-
const navItems = renderNavItems(input.headerNav, 'cg-masthead__menu');
|
|
73
|
-
const headerAction = renderHeaderAction(input.headerAction);
|
|
74
|
-
const footerNav = renderNavItems(input.footerNav, 'cg-colophon__menu');
|
|
75
71
|
const homeHref = escapeAttribute(input.homeHref);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
72
|
+
const sections = navItems(input.headerNav);
|
|
73
|
+
const today = new Date();
|
|
74
|
+
const longToday = escapeText(formatToday(today, input.locale, {
|
|
75
|
+
weekday: 'long',
|
|
76
|
+
year: 'numeric',
|
|
77
|
+
month: 'long',
|
|
78
|
+
day: 'numeric',
|
|
79
|
+
}));
|
|
80
|
+
const shortToday = escapeText(formatToday(today, input.locale, { weekday: 'short', month: 'short', day: 'numeric' }));
|
|
81
|
+
const plate = renderBrandMark(input.brand, { className: 'cg-masthead__logo' }) ??
|
|
82
|
+
`<span class="cg-masthead__name">${siteNameText}</span>`;
|
|
83
|
+
const action = input.headerAction === undefined
|
|
86
84
|
? ''
|
|
87
|
-
: `<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
`</details>`;
|
|
91
|
-
const desktopRubric = !hasRubric
|
|
85
|
+
: `<a class="cg-action cg-masthead__action" data-emphasis="masthead" href="${escapeAttribute(input.headerAction.href)}">${escapeText(input.headerAction.label)}</a>`;
|
|
86
|
+
const toggle = serialize(renderThemeToggle(input.locale, { className: 'cg-theme-toggle' }));
|
|
87
|
+
const tagline = input.tagline === undefined
|
|
92
88
|
? ''
|
|
93
|
-
: `<
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
`<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
: `<p class="cg-masthead__tagline">${escapeText(input.tagline)}</p>`;
|
|
90
|
+
const menu = sections === ''
|
|
91
|
+
? ''
|
|
92
|
+
: `<input type="checkbox" id="cg-nav-toggle" class="cg-nav-toggle-input" aria-label="Menu">` +
|
|
93
|
+
`<label for="cg-nav-toggle" class="cg-nav-toggle-label" aria-hidden="true">` +
|
|
94
|
+
`<span class="cg-nav-toggle-bar"></span><span class="cg-nav-toggle-bar"></span>` +
|
|
95
|
+
`</label>` +
|
|
96
|
+
`<nav class="cg-masthead__nav" id="cg-nav" aria-label="Primary">` +
|
|
97
|
+
`<ul class="cg-masthead__sections">${sections}</ul>` +
|
|
98
|
+
`</nav>`;
|
|
99
|
+
const header = `<header class="cg-masthead" data-nav="${sections === '' ? 'none' : 'sections'}">` +
|
|
100
|
+
`<div class="cg-masthead__bar"><div class="cg-masthead__bar-inner">` +
|
|
101
|
+
`<p class="cg-masthead__date"><time datetime="${isoDay(today)}">` +
|
|
102
|
+
`<span class="cg-masthead__date-long">${longToday}</span>` +
|
|
103
|
+
`<span class="cg-masthead__date-short" aria-hidden="true">${shortToday}</span>` +
|
|
104
|
+
`</time></p>` +
|
|
105
|
+
`${tagline}` +
|
|
106
|
+
`<div class="cg-masthead__tools">${action}${toggle}</div>` +
|
|
107
|
+
`</div></div>` +
|
|
108
|
+
`<div class="cg-masthead__plate">` +
|
|
109
|
+
`<a class="cg-masthead__home" href="${homeHref}">${plate}</a>` +
|
|
102
110
|
`</div>` +
|
|
103
|
-
`${
|
|
111
|
+
`${menu}` +
|
|
104
112
|
`</header>`;
|
|
105
|
-
const
|
|
113
|
+
const footerTagline = input.tagline === undefined
|
|
106
114
|
? ''
|
|
107
115
|
: `<p class="cg-colophon__tagline" data-field="tagline">${escapeText(input.tagline)}</p>`;
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
`<
|
|
123
|
-
|
|
116
|
+
const note = input.footerNote === undefined ? '' : renderFooterNote(input.footerNote);
|
|
117
|
+
const footerLinks = navItems(input.footerNav);
|
|
118
|
+
const social = renderSocialLinks(input.social, {
|
|
119
|
+
className: 'cg-colophon__social',
|
|
120
|
+
itemClassName: 'cg-colophon__social-item',
|
|
121
|
+
});
|
|
122
|
+
const year = today.getFullYear();
|
|
123
|
+
// The footer widget columns (`theme@1.6`) sit under the name, above the
|
|
124
|
+
// colophon's own columns, set in the same register.
|
|
125
|
+
const footerWidgets = renderFooterWidgets(input.widgets, {
|
|
126
|
+
className: 'cg-colophon__widgets',
|
|
127
|
+
headingLevel: 'h2',
|
|
128
|
+
});
|
|
129
|
+
const footer = `<footer class="cg-colophon"><div class="cg-colophon__inner">` +
|
|
130
|
+
`<div class="cg-colophon__plate">` +
|
|
131
|
+
`<a class="cg-colophon__name" href="${homeHref}">${siteNameText}</a>` +
|
|
124
132
|
`</div>` +
|
|
125
|
-
|
|
126
|
-
`<
|
|
127
|
-
`${
|
|
133
|
+
`${footerWidgets === null ? '' : serialize(footerWidgets)}` +
|
|
134
|
+
`<div class="cg-colophon__grid">` +
|
|
135
|
+
`${footerTagline === '' && note === '' ? '' : `<div class="cg-colophon__about">${footerTagline}${note}</div>`}` +
|
|
136
|
+
`${footerLinks === ''
|
|
137
|
+
? ''
|
|
138
|
+
: `<nav class="cg-colophon__nav" aria-label="Footer"><ul class="cg-colophon__links">${footerLinks}</ul></nav>`}` +
|
|
139
|
+
`${social === null ? '' : `<div class="cg-colophon__follow">${serialize(social)}</div>`}` +
|
|
128
140
|
`</div>` +
|
|
129
|
-
`<div class="cg-
|
|
130
|
-
|
|
141
|
+
`<div class="cg-colophon__legal">` +
|
|
142
|
+
`<p class="cg-colophon__copyright">© ${year} ${siteNameText}</p>` +
|
|
131
143
|
`<div class="cg-colophon__branding">${input.brandingHtml}</div>` +
|
|
132
144
|
`</div>` +
|
|
133
145
|
`</div></footer>`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../../src/render/chrome.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,eAAe,EACf,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,GACV,MAAM,oBAAoB,CAAA;AAE3B
|
|
1
|
+
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../../src/render/chrome.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Attributes, type Child, type ContentEntry, type HtmlElement } from '@cogenta/theme-kit';
|
|
2
|
+
/**
|
|
3
|
+
* The frame every block of this theme renders into, and the typographic
|
|
4
|
+
* furniture the blocks share.
|
|
5
|
+
*
|
|
6
|
+
* The outer element carries the section rhythm (`--cg-section`, applied once
|
|
7
|
+
* to every block alike) and paints edge to edge when a variant asks for a
|
|
8
|
+
* band. The inner element is the twelve-column container: a front page, a
|
|
9
|
+
* rail, an article and a colophon all sit on the same columns, so the left
|
|
10
|
+
* edge of a headline, a standfirst and a caption never drift apart.
|
|
11
|
+
*
|
|
12
|
+
* `inner` is `figure` for a block whose semantics are a figure (a quotation
|
|
13
|
+
* and its attribution, a photograph and its caption): `<figcaption>` must be
|
|
14
|
+
* a direct child of its `<figure>`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function section(outer: 'section' | 'div', block: string, className: string, attrs: Attributes, inner: 'div' | 'figure', ...children: readonly Child[]): HtmlElement;
|
|
17
|
+
/**
|
|
18
|
+
* A titled block's head, set the way a newspaper sets a section label: a
|
|
19
|
+
* heavy rule in ink across the grid, the title in the display face under it.
|
|
20
|
+
* `null` for an untitled block, so a caller can drop it into its children.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sectionHead(blockName: string, title: string | undefined): HtmlElement | null;
|
|
23
|
+
/** `September 13, 2026` in the page's locale, or `null` when the value is not a date. */
|
|
24
|
+
export declare function longDate(iso: string, locale: string): string | null;
|
|
25
|
+
/** `Sep 13, 2026`, the form a listing sets under a headline, or `null`. */
|
|
26
|
+
export declare function shortDate(iso: string, locale: string): string | null;
|
|
27
|
+
export declare function entryKicker(entry: ContentEntry): string | undefined;
|
|
28
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/render/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,WAAW,EAGjB,MAAM,oBAAoB,CAAA;AAE3B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CACrB,KAAK,EAAE,SAAS,GAAG,KAAK,EACxB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,KAAK,GAAG,QAAQ,EACvB,GAAG,QAAQ,EAAE,SAAS,KAAK,EAAE,GAC5B,WAAW,CAMb;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAW5F;AAeD,yFAAyF;AACzF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGpE;AAgBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAQnE"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { blockHeadingTag, h, heading, } from '@cogenta/theme-kit';
|
|
2
|
+
/**
|
|
3
|
+
* The frame every block of this theme renders into, and the typographic
|
|
4
|
+
* furniture the blocks share.
|
|
5
|
+
*
|
|
6
|
+
* The outer element carries the section rhythm (`--cg-section`, applied once
|
|
7
|
+
* to every block alike) and paints edge to edge when a variant asks for a
|
|
8
|
+
* band. The inner element is the twelve-column container: a front page, a
|
|
9
|
+
* rail, an article and a colophon all sit on the same columns, so the left
|
|
10
|
+
* edge of a headline, a standfirst and a caption never drift apart.
|
|
11
|
+
*
|
|
12
|
+
* `inner` is `figure` for a block whose semantics are a figure (a quotation
|
|
13
|
+
* and its attribution, a photograph and its caption): `<figcaption>` must be
|
|
14
|
+
* a direct child of its `<figure>`.
|
|
15
|
+
*/
|
|
16
|
+
export function section(outer, block, className, attrs, inner, ...children) {
|
|
17
|
+
return h(outer, { class: `cg-section ${className}`, 'data-block': block, ...attrs }, h(inner, { class: `cg-container ${className}__inner` }, ...children));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A titled block's head, set the way a newspaper sets a section label: a
|
|
21
|
+
* heavy rule in ink across the grid, the title in the display face under it.
|
|
22
|
+
* `null` for an untitled block, so a caller can drop it into its children.
|
|
23
|
+
*/
|
|
24
|
+
export function sectionHead(blockName, title) {
|
|
25
|
+
if (title === undefined)
|
|
26
|
+
return null;
|
|
27
|
+
return h('div', { class: 'cg-head' }, heading(blockHeadingTag(blockName) ?? 'h2', { class: 'cg-head__title', 'data-field': 'title' }, title));
|
|
28
|
+
}
|
|
29
|
+
function parse(iso) {
|
|
30
|
+
const date = new Date(iso);
|
|
31
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
32
|
+
}
|
|
33
|
+
function format(date, locale, options) {
|
|
34
|
+
try {
|
|
35
|
+
return new Intl.DateTimeFormat(locale, { timeZone: 'UTC', ...options }).format(date);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return new Intl.DateTimeFormat('en', { timeZone: 'UTC', ...options }).format(date);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** `September 13, 2026` in the page's locale, or `null` when the value is not a date. */
|
|
42
|
+
export function longDate(iso, locale) {
|
|
43
|
+
const date = parse(iso);
|
|
44
|
+
return date === null ? null : format(date, locale, { dateStyle: 'long' });
|
|
45
|
+
}
|
|
46
|
+
/** `Sep 13, 2026`, the form a listing sets under a headline, or `null`. */
|
|
47
|
+
export function shortDate(iso, locale) {
|
|
48
|
+
const date = parse(iso);
|
|
49
|
+
return date === null ? null : format(date, locale, { dateStyle: 'medium' });
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A taxonomy field stores a term id, never a label: a value shaped like one
|
|
53
|
+
* is not something a reader can be shown.
|
|
54
|
+
*/
|
|
55
|
+
const TERM_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
56
|
+
/**
|
|
57
|
+
* The label a listing sets above a headline, read from whichever of the usual
|
|
58
|
+
* field names a collection declares: `kicker` first (a topic, a form such as
|
|
59
|
+
* "Review", a columnist's name), then the plain-text section fields older
|
|
60
|
+
* schemas use. Never invented, and never a term id.
|
|
61
|
+
*/
|
|
62
|
+
const KICKER_FIELDS = ['kicker', 'rubric', 'section', 'category', 'topic', 'department'];
|
|
63
|
+
export function entryKicker(entry) {
|
|
64
|
+
for (const field of KICKER_FIELDS) {
|
|
65
|
+
const value = entry[field];
|
|
66
|
+
if (typeof value === 'string' && value.trim() !== '' && !TERM_ID.test(value.trim())) {
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/render/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAIf,CAAC,EACD,OAAO,GACR,MAAM,oBAAoB,CAAA;AAE3B;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,OAAO,CACrB,KAAwB,EACxB,KAAa,EACb,SAAiB,EACjB,KAAiB,EACjB,KAAuB,EACvB,GAAG,QAA0B;IAE7B,OAAO,CAAC,CACN,KAAK,EACL,EAAE,KAAK,EAAE,cAAc,SAAS,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EACnE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,SAAS,SAAS,EAAE,EAAE,GAAG,QAAQ,CAAC,CACrE,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,KAAyB;IACtE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACpC,OAAO,CAAC,CACN,KAAK,EACL,EAAE,KAAK,EAAE,SAAS,EAAE,EACpB,OAAO,CACL,eAAe,CAAC,SAAS,CAAC,IAAI,IAAI,EAClC,EAAE,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,OAAO,EAAE,EAClD,KAAK,CACN,CACF,CAAA;AACH,CAAC;AAED,SAAS,KAAK,CAAC,GAAW;IACxB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAA;IAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AACnD,CAAC;AAED,SAAS,MAAM,CAAC,IAAU,EAAE,MAAc,EAAE,OAAmC;IAC7E,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACpF,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,MAAc;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;IACvB,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;AAC3E,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,MAAc;IACnD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;IACvB,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAA;AAC7E,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,GAAG,iEAAiE,CAAA;AAEjF;;;;;GAKG;AACH,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,CAAU,CAAA;AAEjG,MAAM,UAAU,WAAW,CAAC,KAAmB;IAC7C,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACpF,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { type BlockRegistry, type VocabularyBlock } from '@cogenta/blocks';
|
|
2
2
|
import { type FetchedEntries, type HtmlElement, type PageContent, type RenderContext } from '@cogenta/theme-kit';
|
|
3
|
+
export type { FetchedEntries, PageContent };
|
|
3
4
|
export declare function renderBlock(block: VocabularyBlock, ctx: RenderContext, entries?: FetchedEntries, registry?: BlockRegistry): HtmlElement | null;
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* it is what lets the L16 page builder map a clicked element on the real
|
|
8
|
-
* rendered page back to the block that produced it). A page whose blocks
|
|
9
|
-
* already carry a heading (a `hero`) gets no second `<h1>`.
|
|
6
|
+
* `<main id="cg-main">` is mandatory: it is the skip link's target, written
|
|
7
|
+
* by `@cogenta/cli`'s `theme-render.ts` outside any theme's control.
|
|
10
8
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
9
|
+
* Four openings, and exactly one `h1` in each:
|
|
10
|
+
*
|
|
11
|
+
* - a page whose blocks include a `hero` lets the hero carry the title;
|
|
12
|
+
* - an entry that carries what an article has (`isArticle`) gets the
|
|
13
|
+
* article header, and its first `prose` block may open on a drop cap;
|
|
14
|
+
* - a page that opens on a listing is a front: the masthead above already
|
|
15
|
+
* names it, so its title stays in the outline for assistive technology and
|
|
16
|
+
* out of sight, and the first story sits directly under the navigation;
|
|
17
|
+
* - anything else gets its title set as a section title.
|
|
18
|
+
*
|
|
19
|
+
* `withBlockKey` stamps every rendered block with its contract-B `_key`, so
|
|
20
|
+
* the visual page builder (L16) can map a clicked element back to its block.
|
|
19
21
|
*/
|
|
20
22
|
export declare function renderPage(page: PageContent, ctx: RenderContext, entries?: FetchedEntries, registry?: BlockRegistry): HtmlElement;
|
|
21
23
|
//# 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,EAAE,KAAK,aAAa,EAAoB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC5F,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,WAAW,
|
|
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,EAEhB,KAAK,WAAW,EAGhB,KAAK,aAAa,EAInB,MAAM,oBAAoB,CAAA;AAoB3B,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,CAepB;AA2DD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,cAAmB,EAC5B,QAAQ,CAAC,EAAE,aAAa,GACvB,WAAW,CA6Bb"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VOCABULARY_NAMES } from '@cogenta/blocks';
|
|
2
|
-
import { h, pageHasOwnHeading,
|
|
2
|
+
import { h, pageHasOwnHeading, providedBlockNode, resolveBlockForRender, withBlockKey, withBlockVariant, } from '@cogenta/theme-kit';
|
|
3
|
+
import { isArticle, renderArticleFooter, renderArticleHeader, renderPageHeader } from './article.js';
|
|
3
4
|
import { renderAccordion } from './blocks/accordion.js';
|
|
4
5
|
import { renderCollectionList } from './blocks/collection-list.js';
|
|
5
6
|
import { renderCta } from './blocks/cta.js';
|
|
@@ -18,18 +19,21 @@ import { renderStatCounter } from './blocks/stat-counter.js';
|
|
|
18
19
|
import { renderStats } from './blocks/stats.js';
|
|
19
20
|
import { renderTestimonial } from './blocks/testimonial.js';
|
|
20
21
|
export function renderBlock(block, ctx, entries = {}, registry) {
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
22
|
+
// A block a plugin provides arrives already rendered by the host, in a
|
|
23
|
+
// process of its own (contract D theme@1.7). Nothing else in this theme
|
|
24
|
+
// needs to know such blocks exist.
|
|
25
|
+
const provided = providedBlockNode(block, ctx);
|
|
26
|
+
if (provided !== null)
|
|
27
|
+
return withBlockVariant(provided, block.variant);
|
|
28
|
+
// A stored block is not always literally one of the shared vocabulary:
|
|
29
|
+
// resolving here turns an unimplemented theme-private block into its
|
|
30
|
+
// declared fallback instead of a silently blank slot.
|
|
25
31
|
const resolved = resolveBlockForRender(block, VOCABULARY_NAMES, registry);
|
|
26
32
|
if (resolved === null)
|
|
27
33
|
return null;
|
|
28
34
|
const known = resolved;
|
|
29
|
-
// `
|
|
30
|
-
//
|
|
31
|
-
// `variant` is envelope data every block carries identically, exactly the
|
|
32
|
-
// same reasoning `withBlockKey` in `renderPage` already follows for `_key`.
|
|
35
|
+
// `variant` is envelope data every block carries identically, applied
|
|
36
|
+
// once here rather than by each of the seventeen renderers.
|
|
33
37
|
return withBlockVariant(renderKnownBlock(known, ctx, entries), known.variant);
|
|
34
38
|
}
|
|
35
39
|
function renderKnownBlock(known, ctx, entries) {
|
|
@@ -69,36 +73,56 @@ function renderKnownBlock(known, ctx, entries) {
|
|
|
69
73
|
case 'logoStrip':
|
|
70
74
|
return renderLogoStrip(known, ctx);
|
|
71
75
|
default: {
|
|
72
|
-
// Exhaustive over contract B
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
// to reach for (contract D refuses that import), and a fallback block
|
|
76
|
-
// is the render layer's decision, not the theme's.
|
|
76
|
+
// Exhaustive over contract B: `known` is `never` here, so a block this
|
|
77
|
+
// package does not implement stops it compiling until it is. `null`
|
|
78
|
+
// rather than a throw: choosing a fallback is the render layer's job.
|
|
77
79
|
const unreachable = known;
|
|
78
80
|
void unreachable;
|
|
79
81
|
return null;
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
}
|
|
85
|
+
/** Marks the first `prose` block of an article, the one paragraph a drop cap may open. */
|
|
86
|
+
function withOpening(element) {
|
|
87
|
+
if (element === null)
|
|
88
|
+
return null;
|
|
89
|
+
return { ...element, attrs: { ...element.attrs, 'data-opening': 'true' } };
|
|
90
|
+
}
|
|
83
91
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
92
|
+
* `<main id="cg-main">` is mandatory: it is the skip link's target, written
|
|
93
|
+
* by `@cogenta/cli`'s `theme-render.ts` outside any theme's control.
|
|
94
|
+
*
|
|
95
|
+
* Four openings, and exactly one `h1` in each:
|
|
96
|
+
*
|
|
97
|
+
* - a page whose blocks include a `hero` lets the hero carry the title;
|
|
98
|
+
* - an entry that carries what an article has (`isArticle`) gets the
|
|
99
|
+
* article header, and its first `prose` block may open on a drop cap;
|
|
100
|
+
* - a page that opens on a listing is a front: the masthead above already
|
|
101
|
+
* names it, so its title stays in the outline for assistive technology and
|
|
102
|
+
* out of sight, and the first story sits directly under the navigation;
|
|
103
|
+
* - anything else gets its title set as a section title.
|
|
89
104
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* journal-red accent, see `styles/base.css`'s `.cg-entry-header__terms`),
|
|
93
|
-
* title, excerpt, date/author/reading-time meta and cover — instead of the
|
|
94
|
-
* bare `<h1>` every other page falls back to; `renderEntryHeader` itself
|
|
95
|
-
* returns `null` for a `blocks`-only page (e.g. `about`, which carries no
|
|
96
|
-
* `entry`) or one that already draws its own heading, so the bare-title
|
|
97
|
-
* fallback still applies there, exactly as before.
|
|
105
|
+
* `withBlockKey` stamps every rendered block with its contract-B `_key`, so
|
|
106
|
+
* the visual page builder (L16) can map a clicked element back to its block.
|
|
98
107
|
*/
|
|
99
108
|
export function renderPage(page, ctx, entries = {}, registry) {
|
|
100
109
|
const ownHeading = pageHasOwnHeading(page.blocks);
|
|
101
|
-
const
|
|
102
|
-
|
|
110
|
+
const article = !ownHeading && isArticle(page.entry) ? page.entry : undefined;
|
|
111
|
+
const front = !ownHeading && article === undefined && page.blocks[0]?._type === 'collectionList';
|
|
112
|
+
const opening = ownHeading
|
|
113
|
+
? null
|
|
114
|
+
: article !== undefined
|
|
115
|
+
? renderArticleHeader(page, article, ctx)
|
|
116
|
+
: front
|
|
117
|
+
? h('h1', { class: 'cg-visually-hidden' }, page.title)
|
|
118
|
+
: renderPageHeader(page);
|
|
119
|
+
const firstProse = article === undefined ? undefined : page.blocks.find((block) => block._type === 'prose');
|
|
120
|
+
return h('main', {
|
|
121
|
+
class: article !== undefined ? 'cg-main cg-article' : front ? 'cg-main cg-front-page' : 'cg-main',
|
|
122
|
+
id: 'cg-main',
|
|
123
|
+
}, opening, page.blocks.map((block) => {
|
|
124
|
+
const rendered = renderBlock(block, ctx, entries, registry);
|
|
125
|
+
return withBlockKey(block === firstProse ? withOpening(rendered) : rendered, block._key);
|
|
126
|
+
}), article === undefined ? null : renderArticleFooter(article));
|
|
103
127
|
}
|
|
104
128
|
//# sourceMappingURL=render-block.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-block.js","sourceRoot":"","sources":["../../../src/render/render-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,gBAAgB,EAAwB,MAAM,iBAAiB,CAAA;AAC5F,OAAO,EAGL,CAAC,EAED,iBAAiB,
|
|
1
|
+
{"version":3,"file":"render-block.js","sourceRoot":"","sources":["../../../src/render/render-block.ts"],"names":[],"mappings":"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"}
|