@cogenta/theme-association 0.3.2 → 0.5.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 +6 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/render/blocks/accordion.d.ts.map +1 -1
- package/dist/src/render/blocks/accordion.js +13 -10
- package/dist/src/render/blocks/accordion.js.map +1 -1
- package/dist/src/render/blocks/breakdown.d.ts +14 -0
- package/dist/src/render/blocks/breakdown.d.ts.map +1 -0
- package/dist/src/render/blocks/breakdown.js +17 -0
- package/dist/src/render/blocks/breakdown.js.map +1 -0
- package/dist/src/render/blocks/collection-list.d.ts +4 -10
- package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
- package/dist/src/render/blocks/collection-list.js +89 -58
- package/dist/src/render/blocks/collection-list.js.map +1 -1
- package/dist/src/render/blocks/cta.d.ts +0 -5
- package/dist/src/render/blocks/cta.d.ts.map +1 -1
- package/dist/src/render/blocks/cta.js +22 -10
- 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 +30 -22
- 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 +11 -15
- package/dist/src/render/blocks/faq.js.map +1 -1
- package/dist/src/render/blocks/feature-grid.d.ts +6 -0
- package/dist/src/render/blocks/feature-grid.d.ts.map +1 -1
- package/dist/src/render/blocks/feature-grid.js +42 -20
- package/dist/src/render/blocks/feature-grid.js.map +1 -1
- package/dist/src/render/blocks/gallery.d.ts +9 -7
- package/dist/src/render/blocks/gallery.d.ts.map +1 -1
- package/dist/src/render/blocks/gallery.js +22 -16
- package/dist/src/render/blocks/gallery.js.map +1 -1
- package/dist/src/render/blocks/hero.d.ts +23 -9
- package/dist/src/render/blocks/hero.d.ts.map +1 -1
- package/dist/src/render/blocks/hero.js +40 -23
- package/dist/src/render/blocks/hero.js.map +1 -1
- package/dist/src/render/blocks/logo-strip.d.ts +6 -0
- package/dist/src/render/blocks/logo-strip.d.ts.map +1 -1
- package/dist/src/render/blocks/logo-strip.js +7 -9
- package/dist/src/render/blocks/logo-strip.js.map +1 -1
- package/dist/src/render/blocks/logos.d.ts +14 -0
- package/dist/src/render/blocks/logos.d.ts.map +1 -1
- package/dist/src/render/blocks/logos.js +30 -16
- package/dist/src/render/blocks/logos.js.map +1 -1
- package/dist/src/render/blocks/media-figure.d.ts +12 -5
- package/dist/src/render/blocks/media-figure.d.ts.map +1 -1
- package/dist/src/render/blocks/media-figure.js +32 -18
- 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 +18 -20
- package/dist/src/render/blocks/pricing-table.js.map +1 -1
- package/dist/src/render/blocks/prose.d.ts +9 -3
- package/dist/src/render/blocks/prose.d.ts.map +1 -1
- package/dist/src/render/blocks/prose.js +11 -4
- package/dist/src/render/blocks/prose.js.map +1 -1
- package/dist/src/render/blocks/quote.d.ts +4 -7
- package/dist/src/render/blocks/quote.d.ts.map +1 -1
- package/dist/src/render/blocks/quote.js +12 -17
- package/dist/src/render/blocks/quote.js.map +1 -1
- package/dist/src/render/blocks/stat-counter.d.ts +8 -1
- package/dist/src/render/blocks/stat-counter.d.ts.map +1 -1
- package/dist/src/render/blocks/stat-counter.js +18 -10
- package/dist/src/render/blocks/stat-counter.js.map +1 -1
- package/dist/src/render/blocks/stats.d.ts +12 -1
- package/dist/src/render/blocks/stats.d.ts.map +1 -1
- package/dist/src/render/blocks/stats.js +24 -14
- package/dist/src/render/blocks/stats.js.map +1 -1
- package/dist/src/render/blocks/testimonial.d.ts +6 -5
- package/dist/src/render/blocks/testimonial.d.ts.map +1 -1
- package/dist/src/render/blocks/testimonial.js +13 -11
- package/dist/src/render/blocks/testimonial.js.map +1 -1
- package/dist/src/render/chrome.d.ts +38 -1
- package/dist/src/render/chrome.d.ts.map +1 -1
- package/dist/src/render/chrome.js +117 -91
- package/dist/src/render/chrome.js.map +1 -1
- package/dist/src/render/details.d.ts +79 -0
- package/dist/src/render/details.d.ts.map +1 -0
- package/dist/src/render/details.js +221 -0
- package/dist/src/render/details.js.map +1 -0
- package/dist/src/render/figures.d.ts +29 -0
- package/dist/src/render/figures.d.ts.map +1 -0
- package/dist/src/render/figures.js +59 -0
- package/dist/src/render/figures.js.map +1 -0
- package/dist/src/render/layout.d.ts +31 -0
- package/dist/src/render/layout.d.ts.map +1 -0
- package/dist/src/render/layout.js +46 -0
- package/dist/src/render/layout.js.map +1 -0
- package/dist/src/render/page-head.d.ts +7 -0
- package/dist/src/render/page-head.d.ts.map +1 -0
- package/dist/src/render/page-head.js +95 -0
- package/dist/src/render/page-head.js.map +1 -0
- package/dist/src/render/render-block.d.ts +8 -12
- package/dist/src/render/render-block.d.ts.map +1 -1
- package/dist/src/render/render-block.js +40 -29
- package/dist/src/render/render-block.js.map +1 -1
- package/dist/src/render/strings.d.ts +15 -0
- package/dist/src/render/strings.d.ts.map +1 -0
- package/dist/src/render/strings.js +39 -0
- package/dist/src/render/strings.js.map +1 -0
- package/dist/src/render/term-archive.d.ts.map +1 -1
- package/dist/src/render/term-archive.js +33 -25
- package/dist/src/render/term-archive.js.map +1 -1
- package/dist/src/render/widget-areas.d.ts +14 -0
- package/dist/src/render/widget-areas.d.ts.map +1 -0
- package/dist/src/render/widget-areas.js +21 -0
- package/dist/src/render/widget-areas.js.map +1 -0
- package/dist/theme.config.d.ts +1 -1
- package/dist/theme.config.js +3 -3
- package/dist/theme.config.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +9 -0
- package/src/render/blocks/accordion.ts +28 -22
- package/src/render/blocks/breakdown.ts +42 -0
- package/src/render/blocks/collection-list.ts +234 -103
- package/src/render/blocks/cta.ts +48 -19
- package/src/render/blocks/embed.ts +47 -29
- package/src/render/blocks/faq.ts +22 -31
- package/src/render/blocks/feature-grid.ts +73 -41
- package/src/render/blocks/gallery.ts +32 -26
- package/src/render/blocks/hero.ts +56 -43
- package/src/render/blocks/logo-strip.ts +23 -21
- package/src/render/blocks/logos.ts +45 -40
- package/src/render/blocks/media-figure.ts +49 -24
- package/src/render/blocks/pricing-table.ts +31 -40
- package/src/render/blocks/prose.ts +16 -6
- package/src/render/blocks/quote.ts +34 -27
- package/src/render/blocks/stat-counter.ts +35 -29
- package/src/render/blocks/stats.ts +46 -38
- package/src/render/blocks/testimonial.ts +29 -20
- package/src/render/chrome.ts +165 -91
- package/src/render/details.ts +276 -0
- package/src/render/figures.ts +68 -0
- package/src/render/layout.ts +78 -0
- package/src/render/page-head.ts +193 -0
- package/src/render/render-block.ts +45 -32
- package/src/render/strings.ts +74 -0
- package/src/render/term-archive.ts +94 -58
- package/src/render/widget-areas.ts +24 -0
- package/src/styles/archive.css +38 -102
- package/src/styles/base.css +503 -554
- package/src/styles/blocks.css +913 -666
- package/src/styles/chrome.css +506 -0
- package/src/styles/listings.css +591 -0
- package/src/styles/theme.css +25 -19
- package/src/styles/tokens.css +284 -234
- package/src/styles/widgets.css +1059 -0
- package/tokens.json +18 -18
|
@@ -1,106 +1,132 @@
|
|
|
1
|
-
import { escapeAttribute, escapeText, renderBrandMark, renderSocialLinks, renderThemeToggle, serialize, } from '@cogenta/theme-kit';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* rounded, filled action button, and a four-column footer (brand+tagline,
|
|
6
|
-
* navigation, social, a short note) on a tinted band, closing with Cogenta's
|
|
7
|
-
* own credit.
|
|
8
|
-
*
|
|
9
|
-
* The mobile nav is a `<details>`/`<summary>` disclosure — the same
|
|
10
|
-
* zero-JavaScript mechanism `faq`/`accordion` already use — rather than a
|
|
11
|
-
* scripted hamburger: expanding, keyboard operation and the open state
|
|
12
|
-
* announced to assistive technology all come from the browser. The same
|
|
13
|
-
* links are rendered twice (once inside the disclosure, once as a plain
|
|
14
|
-
* inline row) and `src/styles/base.css` shows exactly one of the two at any
|
|
15
|
-
* given width via `display:none` — which also removes the hidden copy from
|
|
16
|
-
* the accessibility tree, so nothing is ever announced twice.
|
|
17
|
-
*
|
|
18
|
-
* `theme@1.4` (L25 D2) fields — `headerAction`, `tagline`, `social`,
|
|
19
|
-
* `footerNote` — are each rendered only when present; a render with none of
|
|
20
|
-
* them set still produces a complete header/footer, exactly the additive
|
|
21
|
-
* guarantee the contract promises.
|
|
22
|
-
*
|
|
23
|
-
* The manual light/dark toggle (`renderThemeToggle`, `@cogenta/theme-kit`,
|
|
24
|
-
* L26) is unconditional — it sits between the desktop nav and the header
|
|
25
|
-
* action, outside the `<details>` mobile disclosure so it stays reachable at
|
|
26
|
-
* every width rather than one tap deep inside the hamburger menu.
|
|
27
|
-
*/
|
|
28
|
-
function navItems(links) {
|
|
29
|
-
return links
|
|
30
|
-
.filter((link) => link.href !== null || link.kind === 'submenu-placeholder')
|
|
31
|
-
.map((link) => {
|
|
32
|
-
const label = escapeText(link.label);
|
|
33
|
-
const titleAttr = link.title === null ? '' : ` title="${escapeAttribute(link.title)}"`;
|
|
34
|
-
if (link.href === null)
|
|
35
|
-
return `<li><span${titleAttr}>${label}</span></li>`;
|
|
36
|
-
const href = escapeAttribute(link.href);
|
|
37
|
-
const target = link.openInNewTab ? ' target="_blank" rel="noopener"' : '';
|
|
38
|
-
return `<li><a href="${href}"${target}${titleAttr}>${label}</a></li>`;
|
|
39
|
-
})
|
|
40
|
-
.join('');
|
|
1
|
+
import { escapeAttribute, escapeText, renderBrandMark, renderFooterWidgets, renderSocialLinks, renderThemeToggle, serialize, } from '@cogenta/theme-kit';
|
|
2
|
+
import { associationString } from './strings.js';
|
|
3
|
+
function usable(links) {
|
|
4
|
+
return links.filter((link) => link.href !== null || link.kind === 'submenu-placeholder');
|
|
41
5
|
}
|
|
42
|
-
function
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
6
|
+
function linkItem(link, className) {
|
|
7
|
+
const label = escapeText(link.label);
|
|
8
|
+
const titleAttr = link.title === null ? '' : ` title="${escapeAttribute(link.title)}"`;
|
|
9
|
+
if (link.href === null)
|
|
10
|
+
return `<li class="${className}"><span${titleAttr}>${label}</span></li>`;
|
|
11
|
+
const target = link.openInNewTab ? ' target="_blank" rel="noopener"' : '';
|
|
12
|
+
return `<li class="${className}"><a href="${escapeAttribute(link.href)}"${target}${titleAttr}>${label}</a></li>`;
|
|
13
|
+
}
|
|
14
|
+
/** The footer menu, split into columns at each unlinked heading. */
|
|
15
|
+
export function footerGroups(links) {
|
|
16
|
+
const groups = [];
|
|
17
|
+
for (const link of usable(links)) {
|
|
18
|
+
if (link.kind === 'submenu-placeholder' && link.href === null) {
|
|
19
|
+
groups.push({ heading: link.label, links: [] });
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const current = groups[groups.length - 1];
|
|
23
|
+
if (current === undefined)
|
|
24
|
+
groups.push({ heading: null, links: [link] });
|
|
25
|
+
else
|
|
26
|
+
current.links.push(link);
|
|
27
|
+
}
|
|
28
|
+
return groups.filter((group) => group.links.length > 0);
|
|
47
29
|
}
|
|
48
|
-
/**
|
|
49
|
-
function
|
|
50
|
-
|
|
30
|
+
/** `footerNote` as paragraphs at blank lines, each keeping its own line breaks. */
|
|
31
|
+
function renderFooterNote(note) {
|
|
32
|
+
const paragraphs = note
|
|
33
|
+
.replace(/\r\n?/g, '\n')
|
|
34
|
+
.split(/\n\s*\n/)
|
|
35
|
+
.map((paragraph) => paragraph
|
|
36
|
+
.split('\n')
|
|
37
|
+
.map((line) => line.trim())
|
|
38
|
+
.filter((line) => line !== ''))
|
|
39
|
+
.filter((lines) => lines.length > 0);
|
|
40
|
+
if (paragraphs.length === 0)
|
|
51
41
|
return '';
|
|
52
|
-
return
|
|
53
|
-
|
|
42
|
+
return `<div class="ca-footer__note">${paragraphs
|
|
43
|
+
.map((lines) => `<p>${lines.map(noteLine).join('<br>')}</p>`)
|
|
44
|
+
.join('')}</div>`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A line of the footer note that is nothing but an email address or a
|
|
48
|
+
* telephone number is what a visitor taps to reach the organisation, so it
|
|
49
|
+
* becomes a link; every other line stays text.
|
|
50
|
+
*/
|
|
51
|
+
function noteLine(line) {
|
|
52
|
+
const text = escapeText(line);
|
|
53
|
+
if (/^[^\s@<>"']+@[^\s@<>"']+\.[a-z]{2,}$/i.test(line)) {
|
|
54
|
+
return `<a href="mailto:${escapeAttribute(line)}">${text}</a>`;
|
|
55
|
+
}
|
|
56
|
+
const digits = line.replace(/[\s().-]/g, '');
|
|
57
|
+
if (/^\+?\d{7,15}$/.test(digits))
|
|
58
|
+
return `<a href="tel:${digits}">${text}</a>`;
|
|
59
|
+
return text;
|
|
54
60
|
}
|
|
55
|
-
/** A plain hamburger glyph — three bars, drawn as `<path>`s so nothing here needs the icon set's closed vocabulary. */
|
|
56
|
-
const MENU_GLYPH = '<svg class="cg-nav-toggle__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">' +
|
|
57
|
-
'<path d="M4 7h16M4 12h16M4 17h16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>' +
|
|
58
|
-
'</svg>';
|
|
59
61
|
export function renderChrome(input) {
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
const themeToggle = serialize(renderThemeToggle(input.locale, { className: 'cg-theme-toggle' }));
|
|
67
|
-
const mobileToggle = headerNavMobile === ''
|
|
62
|
+
const siteName = escapeText(input.site.name);
|
|
63
|
+
const home = escapeAttribute(input.homeHref);
|
|
64
|
+
const links = usable(input.headerNav)
|
|
65
|
+
.map((link) => linkItem(link, 'ca-header__item'))
|
|
66
|
+
.join('');
|
|
67
|
+
const action = input.headerAction === undefined
|
|
68
68
|
? ''
|
|
69
|
-
: `<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
: `<a class="ca-header__action" href="${escapeAttribute(input.headerAction.href)}">${escapeText(input.headerAction.label)}</a>`;
|
|
70
|
+
const toggle = serialize(renderThemeToggle(input.locale, { className: 'cg-theme-toggle' }));
|
|
71
|
+
const logo = renderBrandMark(input.brand, { className: 'ca-header__logo' });
|
|
72
|
+
const mark = logo ?? `<span class="ca-header__wordmark">${siteName}</span>`;
|
|
73
|
+
const panelTagline = input.tagline === undefined
|
|
74
|
+
? ''
|
|
75
|
+
: `<p class="ca-header__tagline">${escapeText(input.tagline)}</p>`;
|
|
76
|
+
const menu = links === ''
|
|
77
|
+
? ''
|
|
78
|
+
: `<input type="checkbox" id="ca-nav-toggle" class="ca-nav-toggle-input" aria-label="${escapeAttribute(associationString(input.locale, 'menu'))}">` +
|
|
79
|
+
`<label for="ca-nav-toggle" class="ca-nav-toggle-label" aria-hidden="true">` +
|
|
80
|
+
`<span class="ca-nav-toggle-open">${escapeText(associationString(input.locale, 'menu'))}</span>` +
|
|
81
|
+
`<span class="ca-nav-toggle-close">${escapeText(associationString(input.locale, 'close'))}</span>` +
|
|
82
|
+
`</label>` +
|
|
83
|
+
`<nav class="ca-header__nav" id="ca-nav" aria-label="${escapeAttribute(associationString(input.locale, 'primaryNav'))}">` +
|
|
84
|
+
`<ul class="ca-header__links">${links}</ul>` +
|
|
85
|
+
`${panelTagline}` +
|
|
86
|
+
`</nav>`;
|
|
87
|
+
const header = `<header class="ca-header" data-nav="${links === '' ? 'none' : 'links'}" data-action="${action === '' ? 'none' : 'link'}">` +
|
|
88
|
+
`<div class="ca-header__inner">` +
|
|
89
|
+
`<a class="ca-header__brand" href="${home}">${mark}</a>` +
|
|
90
|
+
`${menu}` +
|
|
91
|
+
`${action}` +
|
|
92
|
+
`${toggle}` +
|
|
79
93
|
`</div></header>`;
|
|
80
94
|
const tagline = input.tagline === undefined
|
|
81
95
|
? ''
|
|
82
|
-
: `<p class="
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
96
|
+
: `<p class="ca-footer__tagline" data-field="tagline">${escapeText(input.tagline)}</p>`;
|
|
97
|
+
const note = input.footerNote === undefined ? '' : renderFooterNote(input.footerNote);
|
|
98
|
+
const social = renderSocialLinks(input.social, {
|
|
99
|
+
className: 'ca-footer__social',
|
|
100
|
+
itemClassName: 'ca-footer__social-item',
|
|
101
|
+
});
|
|
102
|
+
const groups = footerGroups(input.footerNav);
|
|
103
|
+
const nav = groups.length === 0
|
|
90
104
|
? ''
|
|
91
|
-
: `<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
: `<nav class="ca-footer__nav" aria-label="${escapeAttribute(associationString(input.locale, 'footerNav'))}" data-columns="${Math.min(groups.length, 3)}">${groups
|
|
106
|
+
.map((group) => `<div class="ca-footer__group">${group.heading === null
|
|
107
|
+
? ''
|
|
108
|
+
: `<p class="ca-footer__heading">${escapeText(group.heading)}</p>`}<ul class="ca-footer__links">${group.links
|
|
109
|
+
.map((link) => linkItem(link, 'ca-footer__item'))
|
|
110
|
+
.join('')}</ul></div>`)
|
|
111
|
+
.join('')}</nav>`;
|
|
112
|
+
const year = new Date().getFullYear();
|
|
113
|
+
const widgets = renderFooterWidgets(input.widgets, {
|
|
114
|
+
className: 'ca-footer__widgets',
|
|
115
|
+
headingLevel: 'h2',
|
|
116
|
+
});
|
|
117
|
+
const footer = `<footer class="ca-footer"><div class="ca-footer__inner">` +
|
|
118
|
+
`<div class="ca-footer__about">` +
|
|
119
|
+
`<a class="ca-footer__name" href="${home}">${siteName}</a>` +
|
|
120
|
+
`${tagline}${note}` +
|
|
121
|
+
`${social === null ? '' : serialize(social)}` +
|
|
97
122
|
`</div>` +
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
`<div class="
|
|
123
|
+
`${nav}` +
|
|
124
|
+
`${widgets === null ? '' : serialize(widgets)}` +
|
|
125
|
+
`<div class="ca-footer__legal">` +
|
|
126
|
+
`<p class="ca-footer__copyright">© ${year} ${siteName}</p>` +
|
|
127
|
+
`${input.brandingHtml === '' ? '' : `<div class="ca-footer__branding">${input.brandingHtml}</div>`}` +
|
|
101
128
|
`</div>` +
|
|
102
|
-
|
|
103
|
-
`</footer>`;
|
|
129
|
+
`</div></footer>`;
|
|
104
130
|
return { header, footer };
|
|
105
131
|
}
|
|
106
132
|
//# sourceMappingURL=chrome.js.map
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../../src/render/chrome.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type HtmlElement } from '@cogenta/theme-kit';
|
|
2
|
+
/**
|
|
3
|
+
* Reading an event's date and a programme's practical details out of plain
|
|
4
|
+
* content data.
|
|
5
|
+
*
|
|
6
|
+
* Contract A fixes the system fields and nothing else, so a theme can only
|
|
7
|
+
* recognise these by convention: an entry with a date in `startsAt`, `start`,
|
|
8
|
+
* `date` or `eventDate` is something that happens on a day, and its
|
|
9
|
+
* `location`, `address`, `cost` and `booking` fields say where and how to
|
|
10
|
+
* come. The same convention reads an event in a list (the raw entry) and on
|
|
11
|
+
* its own page (`theme@1.5`'s `PageEntryMeta.fields`), so the two can never
|
|
12
|
+
* disagree about a date.
|
|
13
|
+
*
|
|
14
|
+
* Dates are written in UTC. Contract D carries no site time zone, and a
|
|
15
|
+
* server's own zone is an accident of where it happens to run; a stored
|
|
16
|
+
* `2026-10-15T18:00:00Z` therefore reads "6pm" on every server, which is
|
|
17
|
+
* what an editor who typed six o'clock meant.
|
|
18
|
+
*/
|
|
19
|
+
export declare const START_FIELDS: readonly ['startsAt', 'start', 'date', 'eventDate'];
|
|
20
|
+
export declare const END_FIELDS: readonly ['endsAt', 'end'];
|
|
21
|
+
type Source = Readonly<Record<string, unknown>>;
|
|
22
|
+
export interface Moment {
|
|
23
|
+
readonly iso: string;
|
|
24
|
+
readonly date: Date;
|
|
25
|
+
/** `false` for a bare `YYYY-MM-DD`: the day is known, the hour is not. */
|
|
26
|
+
readonly hasTime: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface EventTime {
|
|
29
|
+
readonly start: Moment;
|
|
30
|
+
readonly end: Moment | undefined;
|
|
31
|
+
}
|
|
32
|
+
/** A non-empty string, trimmed, or `undefined`. */
|
|
33
|
+
export declare function textOf(value: unknown): string | undefined;
|
|
34
|
+
/** The start (and end, when there is one after it) of whatever this entry says happens. */
|
|
35
|
+
export declare function eventTimeOf(source: Source | undefined): EventTime | undefined;
|
|
36
|
+
export declare function dayOf(moment: Moment, locale: string): string;
|
|
37
|
+
export declare function monthOf(moment: Moment, locale: string): string;
|
|
38
|
+
export declare function weekdayOf(moment: Moment, locale: string): string;
|
|
39
|
+
export declare function yearOf(moment: Moment, locale: string): string;
|
|
40
|
+
export declare function longDateOf(moment: Moment, locale: string): string;
|
|
41
|
+
export declare function fullDateOf(moment: Moment, locale: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* A time of day the way a charity's own printed copy writes it. A locale
|
|
44
|
+
* whose clock is twelve-hour reads "6pm", "7.30pm", "10am": lowercase, no
|
|
45
|
+
* ":00", a dot before the minutes. A locale whose clock is twenty-four-hour
|
|
46
|
+
* keeps the platform's own form ("18:30"). Which clock a locale uses comes
|
|
47
|
+
* from `Intl`, never from a list of countries.
|
|
48
|
+
*/
|
|
49
|
+
export declare function timeOf(moment: Moment, locale: string): string;
|
|
50
|
+
/** "6pm to 7.30pm", "6pm", or `undefined` for an event with no hour. */
|
|
51
|
+
export declare function hoursOf(time: EventTime, locale: string): string | undefined;
|
|
52
|
+
export declare function placeOf(source: Source): string | undefined;
|
|
53
|
+
export interface Fact {
|
|
54
|
+
readonly key: string;
|
|
55
|
+
readonly label: string;
|
|
56
|
+
readonly value: string;
|
|
57
|
+
/** A second line under the value: the street address under the name of a hall. */
|
|
58
|
+
readonly detail?: string;
|
|
59
|
+
readonly href?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The practical details a visitor looks for before they come, in the order
|
|
63
|
+
* they look: when, where, who it is for, what it costs, whether to book, and
|
|
64
|
+
* who to ask. An event's "when" is its date; a programme's is its schedule.
|
|
65
|
+
* Only what the entry actually says is listed.
|
|
66
|
+
*/
|
|
67
|
+
export declare function factsOf(source: Source, locale: string): readonly Fact[];
|
|
68
|
+
/** The details as a definition list, or `null` when the entry says none of them. */
|
|
69
|
+
export declare function renderFacts(facts: readonly Fact[], className: string): HtmlElement | null;
|
|
70
|
+
/**
|
|
71
|
+
* The typographic date block: the day large, the month in small capitals,
|
|
72
|
+
* the weekday under them. The whole block is one `<time>`, so a reader hears
|
|
73
|
+
* one date rather than three loose words.
|
|
74
|
+
*/
|
|
75
|
+
export declare function renderDateBlock(time: EventTime, locale: string, className: string, options?: {
|
|
76
|
+
readonly year?: boolean;
|
|
77
|
+
}): HtmlElement;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=details.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"details.d.ts","sourceRoot":"","sources":["../../../src/render/details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAK,MAAM,oBAAoB,CAAA;AAGxD;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,YAAY,YAAI,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAU,CAAA;AAC/E,eAAO,MAAM,UAAU,YAAI,QAAQ,EAAE,KAAK,CAAU,CAAA;AAKpD,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAE/C,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC;AAED,mDAAmD;AACnD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIzD;AAkBD,2FAA2F;AAC3F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAc7E;AAWD,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAgB7D;AAED,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ3E;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1D;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AASD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CA4CvE;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAqBzF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC,WAAW,CAcb"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { h } from '@cogenta/theme-kit';
|
|
2
|
+
import { associationString } from './strings.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reading an event's date and a programme's practical details out of plain
|
|
5
|
+
* content data.
|
|
6
|
+
*
|
|
7
|
+
* Contract A fixes the system fields and nothing else, so a theme can only
|
|
8
|
+
* recognise these by convention: an entry with a date in `startsAt`, `start`,
|
|
9
|
+
* `date` or `eventDate` is something that happens on a day, and its
|
|
10
|
+
* `location`, `address`, `cost` and `booking` fields say where and how to
|
|
11
|
+
* come. The same convention reads an event in a list (the raw entry) and on
|
|
12
|
+
* its own page (`theme@1.5`'s `PageEntryMeta.fields`), so the two can never
|
|
13
|
+
* disagree about a date.
|
|
14
|
+
*
|
|
15
|
+
* Dates are written in UTC. Contract D carries no site time zone, and a
|
|
16
|
+
* server's own zone is an accident of where it happens to run; a stored
|
|
17
|
+
* `2026-10-15T18:00:00Z` therefore reads "6pm" on every server, which is
|
|
18
|
+
* what an editor who typed six o'clock meant.
|
|
19
|
+
*/
|
|
20
|
+
export const START_FIELDS = ['startsAt', 'start', 'date', 'eventDate'];
|
|
21
|
+
export const END_FIELDS = ['endsAt', 'end'];
|
|
22
|
+
const PLACE_FIELDS = ['location', 'venue', 'place'];
|
|
23
|
+
const SCHEDULE_FIELDS = ['schedule', 'when', 'hours'];
|
|
24
|
+
/** A non-empty string, trimmed, or `undefined`. */
|
|
25
|
+
export function textOf(value) {
|
|
26
|
+
if (typeof value !== 'string')
|
|
27
|
+
return undefined;
|
|
28
|
+
const trimmed = value.trim();
|
|
29
|
+
return trimmed === '' ? undefined : trimmed;
|
|
30
|
+
}
|
|
31
|
+
function firstText(source, names) {
|
|
32
|
+
for (const name of names) {
|
|
33
|
+
const value = textOf(source[name]);
|
|
34
|
+
if (value !== undefined)
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
function momentOf(value) {
|
|
40
|
+
const text = textOf(value);
|
|
41
|
+
if (text === undefined || !/^\d{4}-\d{2}-\d{2}/.test(text))
|
|
42
|
+
return undefined;
|
|
43
|
+
const date = new Date(text);
|
|
44
|
+
if (Number.isNaN(date.getTime()))
|
|
45
|
+
return undefined;
|
|
46
|
+
return { iso: text, date, hasTime: /T\d{2}:\d{2}/.test(text) };
|
|
47
|
+
}
|
|
48
|
+
/** The start (and end, when there is one after it) of whatever this entry says happens. */
|
|
49
|
+
export function eventTimeOf(source) {
|
|
50
|
+
if (source === undefined)
|
|
51
|
+
return undefined;
|
|
52
|
+
let start;
|
|
53
|
+
for (const name of START_FIELDS) {
|
|
54
|
+
start = momentOf(source[name]);
|
|
55
|
+
if (start !== undefined)
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
if (start === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
let end;
|
|
61
|
+
for (const name of END_FIELDS) {
|
|
62
|
+
end = momentOf(source[name]);
|
|
63
|
+
if (end !== undefined)
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
return { start, end: end !== undefined && end.date > start.date ? end : undefined };
|
|
67
|
+
}
|
|
68
|
+
function format(date, locale, options) {
|
|
69
|
+
const resolved = { ...options, timeZone: 'UTC' };
|
|
70
|
+
try {
|
|
71
|
+
return new Intl.DateTimeFormat(locale, resolved).format(date);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return new Intl.DateTimeFormat('en', resolved).format(date);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function dayOf(moment, locale) {
|
|
78
|
+
return format(moment.date, locale, { day: 'numeric' });
|
|
79
|
+
}
|
|
80
|
+
export function monthOf(moment, locale) {
|
|
81
|
+
return format(moment.date, locale, { month: 'short' }).replace(/\.$/, '');
|
|
82
|
+
}
|
|
83
|
+
export function weekdayOf(moment, locale) {
|
|
84
|
+
return format(moment.date, locale, { weekday: 'short' }).replace(/\.$/, '');
|
|
85
|
+
}
|
|
86
|
+
export function yearOf(moment, locale) {
|
|
87
|
+
return format(moment.date, locale, { year: 'numeric' });
|
|
88
|
+
}
|
|
89
|
+
export function longDateOf(moment, locale) {
|
|
90
|
+
return format(moment.date, locale, { weekday: 'long', day: 'numeric', month: 'long' });
|
|
91
|
+
}
|
|
92
|
+
export function fullDateOf(moment, locale) {
|
|
93
|
+
return format(moment.date, locale, {
|
|
94
|
+
weekday: 'long',
|
|
95
|
+
day: 'numeric',
|
|
96
|
+
month: 'long',
|
|
97
|
+
year: 'numeric',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A time of day the way a charity's own printed copy writes it. A locale
|
|
102
|
+
* whose clock is twelve-hour reads "6pm", "7.30pm", "10am": lowercase, no
|
|
103
|
+
* ":00", a dot before the minutes. A locale whose clock is twenty-four-hour
|
|
104
|
+
* keeps the platform's own form ("18:30"). Which clock a locale uses comes
|
|
105
|
+
* from `Intl`, never from a list of countries.
|
|
106
|
+
*/
|
|
107
|
+
export function timeOf(moment, locale) {
|
|
108
|
+
let resolved;
|
|
109
|
+
try {
|
|
110
|
+
resolved = new Intl.DateTimeFormat(locale, { hour: 'numeric', timeZone: 'UTC' });
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
resolved = new Intl.DateTimeFormat('en', { hour: 'numeric', timeZone: 'UTC' });
|
|
114
|
+
}
|
|
115
|
+
const cycle = resolved.resolvedOptions().hourCycle;
|
|
116
|
+
if (cycle !== 'h12' && cycle !== 'h11') {
|
|
117
|
+
return format(moment.date, locale, { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' });
|
|
118
|
+
}
|
|
119
|
+
const hours = moment.date.getUTCHours();
|
|
120
|
+
const minutes = moment.date.getUTCMinutes();
|
|
121
|
+
const hour = hours % 12 === 0 ? 12 : hours % 12;
|
|
122
|
+
const suffix = hours < 12 ? 'am' : 'pm';
|
|
123
|
+
return minutes === 0 ? `${hour}${suffix}` : `${hour}.${String(minutes).padStart(2, '0')}${suffix}`;
|
|
124
|
+
}
|
|
125
|
+
/** "6pm to 7.30pm", "6pm", or `undefined` for an event with no hour. */
|
|
126
|
+
export function hoursOf(time, locale) {
|
|
127
|
+
if (!time.start.hasTime)
|
|
128
|
+
return undefined;
|
|
129
|
+
const start = timeOf(time.start, locale);
|
|
130
|
+
const end = time.end;
|
|
131
|
+
if (end === undefined || !end.hasTime)
|
|
132
|
+
return start;
|
|
133
|
+
const sameDay = end.date.toISOString().slice(0, 10) === time.start.date.toISOString().slice(0, 10);
|
|
134
|
+
if (!sameDay)
|
|
135
|
+
return start;
|
|
136
|
+
return associationString(locale, 'timeRange', { start, end: timeOf(end, locale) });
|
|
137
|
+
}
|
|
138
|
+
export function placeOf(source) {
|
|
139
|
+
return firstText(source, PLACE_FIELDS);
|
|
140
|
+
}
|
|
141
|
+
function contactHref(value) {
|
|
142
|
+
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
|
|
143
|
+
return `mailto:${value}`;
|
|
144
|
+
const digits = value.replace(/[\s().-]/g, '');
|
|
145
|
+
if (/^\+?\d{7,15}$/.test(digits))
|
|
146
|
+
return `tel:${digits}`;
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The practical details a visitor looks for before they come, in the order
|
|
151
|
+
* they look: when, where, who it is for, what it costs, whether to book, and
|
|
152
|
+
* who to ask. An event's "when" is its date; a programme's is its schedule.
|
|
153
|
+
* Only what the entry actually says is listed.
|
|
154
|
+
*/
|
|
155
|
+
export function factsOf(source, locale) {
|
|
156
|
+
const facts = [];
|
|
157
|
+
const time = eventTimeOf(source);
|
|
158
|
+
if (time !== undefined) {
|
|
159
|
+
const hours = hoursOf(time, locale);
|
|
160
|
+
facts.push({
|
|
161
|
+
key: 'when',
|
|
162
|
+
label: associationString(locale, 'when'),
|
|
163
|
+
value: fullDateOf(time.start, locale),
|
|
164
|
+
...(hours === undefined ? {} : { detail: hours }),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const schedule = firstText(source, SCHEDULE_FIELDS);
|
|
169
|
+
if (schedule !== undefined) {
|
|
170
|
+
facts.push({ key: 'when', label: associationString(locale, 'when'), value: schedule });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const place = placeOf(source);
|
|
174
|
+
const address = textOf(source.address);
|
|
175
|
+
if (place !== undefined) {
|
|
176
|
+
facts.push({
|
|
177
|
+
key: 'where',
|
|
178
|
+
label: associationString(locale, 'where'),
|
|
179
|
+
value: place,
|
|
180
|
+
...(address === undefined ? {} : { detail: address }),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else if (address !== undefined) {
|
|
184
|
+
facts.push({ key: 'where', label: associationString(locale, 'address'), value: address });
|
|
185
|
+
}
|
|
186
|
+
for (const key of ['audience', 'cost', 'booking']) {
|
|
187
|
+
const value = textOf(source[key]);
|
|
188
|
+
if (value !== undefined)
|
|
189
|
+
facts.push({ key, label: associationString(locale, key), value });
|
|
190
|
+
}
|
|
191
|
+
const contact = textOf(source.contact);
|
|
192
|
+
if (contact !== undefined) {
|
|
193
|
+
const href = contactHref(contact);
|
|
194
|
+
facts.push({
|
|
195
|
+
key: 'contact',
|
|
196
|
+
label: associationString(locale, 'contact'),
|
|
197
|
+
value: contact,
|
|
198
|
+
...(href === undefined ? {} : { href }),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return facts;
|
|
202
|
+
}
|
|
203
|
+
/** The details as a definition list, or `null` when the entry says none of them. */
|
|
204
|
+
export function renderFacts(facts, className) {
|
|
205
|
+
if (facts.length === 0)
|
|
206
|
+
return null;
|
|
207
|
+
return h('dl', { class: className, 'data-count': String(Math.min(facts.length, 4)) }, facts.map((fact) => h('div', { class: `${className}-item`, 'data-fact': fact.key }, h('dt', { class: `${className}-label` }, fact.label), h('dd', { class: `${className}-value` }, fact.href === undefined ? fact.value : h('a', { href: fact.href }, fact.value), fact.detail === undefined
|
|
208
|
+
? null
|
|
209
|
+
: h('span', { class: `${className}-detail` }, fact.detail)))));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The typographic date block: the day large, the month in small capitals,
|
|
213
|
+
* the weekday under them. The whole block is one `<time>`, so a reader hears
|
|
214
|
+
* one date rather than three loose words.
|
|
215
|
+
*/
|
|
216
|
+
export function renderDateBlock(time, locale, className, options = {}) {
|
|
217
|
+
return h('time', { class: className, datetime: time.start.iso }, h('span', { class: `${className}-month` }, monthOf(time.start, locale)), h('span', { class: `${className}-day` }, dayOf(time.start, locale)), h('span', { class: `${className}-weekday` }, options.year === true
|
|
218
|
+
? `${weekdayOf(time.start, locale)} ${yearOf(time.start, locale)}`
|
|
219
|
+
: weekdayOf(time.start, locale)));
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=details.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"details.js","sourceRoot":"","sources":["../../../src/render/details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,CAAC,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAU,CAAA;AAC/E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAA;AAEpD,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAU,CAAA;AAC5D,MAAM,eAAe,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAU,CAAA;AAgB9D,mDAAmD;AACnD,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAA;AAC7C,CAAC;AAED,SAAS,SAAS,CAAC,MAAc,EAAE,KAAwB;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;QAClC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAA;IACvC,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1B,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IAC5E,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,SAAS,CAAA;IAClD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AAChE,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,WAAW,CAAC,MAA0B;IACpD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC1C,IAAI,KAAyB,CAAA;IAC7B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9B,IAAI,KAAK,KAAK,SAAS;YAAE,MAAK;IAChC,CAAC;IACD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACzC,IAAI,GAAuB,CAAA;IAC3B,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5B,IAAI,GAAG,KAAK,SAAS;YAAE,MAAK;IAC9B,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;AACrF,CAAC;AAED,SAAS,MAAM,CAAC,IAAU,EAAE,MAAc,EAAE,OAAmC;IAC7E,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC7D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,MAAc,EAAE,MAAc;IAClD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc;IACpD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAC3E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,MAAc;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAC7E,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAc,EAAE,MAAc;IACnD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,MAAc;IACvD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;AACxF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,MAAc;IACvD,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE;QACjC,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,SAAS;KAChB,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,MAAc,EAAE,MAAc;IACnD,IAAI,QAA6B,CAAA;IACjC,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,EAAE,CAAC,SAAS,CAAA;IAClD,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACvC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;IAC9F,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAA;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAA;IAC3C,MAAM,IAAI,GAAG,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAA;IAC/C,MAAM,MAAM,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IACvC,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE,CAAA;AACpG,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,OAAO,CAAC,IAAe,EAAE,MAAc;IACrD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,SAAS,CAAA;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IACpB,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IACnD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAClG,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAC1B,OAAO,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA;AACpF,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,OAAO,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;AACxC,CAAC;AAWD,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,UAAU,KAAK,EAAE,CAAA;IACtE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IAC7C,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,OAAO,MAAM,EAAE,CAAA;IACxD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc;IACpD,MAAM,KAAK,GAAW,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QACnC,KAAK,CAAC,IAAI,CAAC;YACT,GAAG,EAAE,MAAM;YACX,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC;YACxC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;YACrC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;SAClD,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;QACnD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QACxF,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC;YACT,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC;YACzC,KAAK,EAAE,KAAK;YACZ,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;SACtD,CAAC,CAAA;IACJ,CAAC;SAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3F,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAU,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;QACjC,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5F,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;QACjC,KAAK,CAAC,IAAI,CAAC;YACT,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC;YAC3C,KAAK,EAAE,OAAO;YACd,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;SACxC,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,WAAW,CAAC,KAAsB,EAAE,SAAiB;IACnE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,OAAO,CAAC,CACN,IAAI,EACJ,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EACrE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACjB,CAAC,CACC,KAAK,EACL,EAAE,KAAK,EAAE,GAAG,SAAS,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EACrD,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,SAAS,QAAQ,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EACpD,CAAC,CACC,IAAI,EACJ,EAAE,KAAK,EAAE,GAAG,SAAS,QAAQ,EAAE,EAC/B,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAC9E,IAAI,CAAC,MAAM,KAAK,SAAS;QACvB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,SAAS,SAAS,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAC7D,CACF,CACF,CACF,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAe,EACf,MAAc,EACd,SAAiB,EACjB,OAAO,GAAgC,EAAE;IAEzC,OAAO,CAAC,CACN,MAAM,EACN,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAC9C,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,SAAS,QAAQ,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,EACvE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,SAAS,MAAM,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,EACnE,CAAC,CACC,MAAM,EACN,EAAE,KAAK,EAAE,GAAG,SAAS,UAAU,EAAE,EACjC,OAAO,CAAC,IAAI,KAAK,IAAI;QACnB,CAAC,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;QAClE,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAClC,CACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two readings of plain text a charity writes all the time, recognised from
|
|
3
|
+
* the words themselves rather than from a setting contract B does not have.
|
|
4
|
+
*
|
|
5
|
+
* - **A breakdown.** Figures that are all percentages and add up to a whole
|
|
6
|
+
* (95 to 105, for rounding) say where the money goes: they are drawn as
|
|
7
|
+
* shares of one total, with a bar each, instead of four unrelated numbers.
|
|
8
|
+
* - **What a gift pays for.** A call to action whose sentences start with an
|
|
9
|
+
* amount of money ("£12 buys a week of fresh vegetables for one family.")
|
|
10
|
+
* lists those amounts large beside what they pay for. Any other text stays
|
|
11
|
+
* the paragraph it was written as.
|
|
12
|
+
*/
|
|
13
|
+
export declare function shareOf(value: string, unit: string | undefined): number | undefined;
|
|
14
|
+
export declare function isBreakdown(items: readonly {
|
|
15
|
+
readonly value: string;
|
|
16
|
+
readonly unit?: string | undefined;
|
|
17
|
+
}[]): boolean;
|
|
18
|
+
export interface Gift {
|
|
19
|
+
readonly amount: string;
|
|
20
|
+
readonly text: string;
|
|
21
|
+
}
|
|
22
|
+
export interface GiftList {
|
|
23
|
+
readonly lead: string | undefined;
|
|
24
|
+
readonly gifts: readonly Gift[];
|
|
25
|
+
readonly tail: string | undefined;
|
|
26
|
+
}
|
|
27
|
+
/** The sentences of `text` that start with an amount, or `undefined` when fewer than two do. */
|
|
28
|
+
export declare function giftsOf(text: string | undefined): GiftList | undefined;
|
|
29
|
+
//# sourceMappingURL=figures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figures.d.ts","sourceRoot":"","sources":["../../../src/render/figures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAMnF;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EAAE,GAC/E,OAAO,CAMT;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAClC;AAID,gGAAgG;AAChG,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAsBtE"}
|