@cogenta/theme-restaurant 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 +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/blocks/accordion.d.ts +7 -0
- package/dist/src/render/blocks/accordion.d.ts.map +1 -1
- package/dist/src/render/blocks/accordion.js +10 -16
- package/dist/src/render/blocks/accordion.js.map +1 -1
- package/dist/src/render/blocks/collection-list.d.ts +4 -11
- package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
- package/dist/src/render/blocks/collection-list.js +96 -96
- package/dist/src/render/blocks/collection-list.js.map +1 -1
- package/dist/src/render/blocks/cta.d.ts +7 -4
- package/dist/src/render/blocks/cta.d.ts.map +1 -1
- package/dist/src/render/blocks/cta.js +9 -7
- 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 -28
- package/dist/src/render/blocks/embed.js.map +1 -1
- package/dist/src/render/blocks/faq.d.ts +13 -1
- package/dist/src/render/blocks/faq.d.ts.map +1 -1
- package/dist/src/render/blocks/faq.js +15 -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 +43 -16
- package/dist/src/render/blocks/feature-grid.js.map +1 -1
- package/dist/src/render/blocks/gallery.d.ts +0 -7
- package/dist/src/render/blocks/gallery.d.ts.map +1 -1
- package/dist/src/render/blocks/gallery.js +28 -10
- package/dist/src/render/blocks/gallery.js.map +1 -1
- package/dist/src/render/blocks/hero.d.ts +16 -9
- package/dist/src/render/blocks/hero.d.ts.map +1 -1
- package/dist/src/render/blocks/hero.js +27 -20
- 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 +8 -0
- package/dist/src/render/blocks/logos.d.ts.map +1 -1
- package/dist/src/render/blocks/logos.js +18 -18
- package/dist/src/render/blocks/logos.js.map +1 -1
- package/dist/src/render/blocks/media-figure.d.ts +14 -3
- package/dist/src/render/blocks/media-figure.d.ts.map +1 -1
- package/dist/src/render/blocks/media-figure.js +34 -16
- 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 +17 -22
- package/dist/src/render/blocks/pricing-table.js.map +1 -1
- package/dist/src/render/blocks/prose.d.ts +11 -6
- package/dist/src/render/blocks/prose.d.ts.map +1 -1
- package/dist/src/render/blocks/prose.js +13 -7
- package/dist/src/render/blocks/prose.js.map +1 -1
- package/dist/src/render/blocks/quote.d.ts +6 -2
- package/dist/src/render/blocks/quote.d.ts.map +1 -1
- package/dist/src/render/blocks/quote.js +14 -12
- package/dist/src/render/blocks/quote.js.map +1 -1
- package/dist/src/render/blocks/stat-counter.d.ts +6 -0
- package/dist/src/render/blocks/stat-counter.d.ts.map +1 -1
- package/dist/src/render/blocks/stat-counter.js +7 -10
- package/dist/src/render/blocks/stat-counter.js.map +1 -1
- package/dist/src/render/blocks/stats.d.ts +7 -0
- package/dist/src/render/blocks/stats.d.ts.map +1 -1
- package/dist/src/render/blocks/stats.js +8 -16
- package/dist/src/render/blocks/stats.js.map +1 -1
- package/dist/src/render/blocks/testimonial.d.ts +5 -11
- package/dist/src/render/blocks/testimonial.d.ts.map +1 -1
- package/dist/src/render/blocks/testimonial.js +9 -17
- 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 +101 -84
- package/dist/src/render/chrome.js.map +1 -1
- package/dist/src/render/dish.d.ts +13 -0
- package/dist/src/render/dish.d.ts.map +1 -0
- package/dist/src/render/dish.js +84 -0
- package/dist/src/render/dish.js.map +1 -0
- package/dist/src/render/layout.d.ts +23 -0
- package/dist/src/render/layout.d.ts.map +1 -0
- package/dist/src/render/layout.js +33 -0
- package/dist/src/render/layout.js.map +1 -0
- package/dist/src/render/menu.d.ts +53 -0
- package/dist/src/render/menu.d.ts.map +1 -0
- package/dist/src/render/menu.js +99 -0
- package/dist/src/render/menu.js.map +1 -0
- package/dist/src/render/render-block.d.ts +19 -0
- package/dist/src/render/render-block.d.ts.map +1 -1
- package/dist/src/render/render-block.js +50 -39
- 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 +23 -0
- package/dist/src/render/strings.js.map +1 -0
- package/dist/src/render/term-archive.d.ts +10 -4
- package/dist/src/render/term-archive.d.ts.map +1 -1
- package/dist/src/render/term-archive.js +25 -16
- package/dist/src/render/term-archive.js.map +1 -1
- package/dist/src/render/widget-areas.d.ts +13 -0
- package/dist/src/render/widget-areas.d.ts.map +1 -0
- package/dist/src/render/widget-areas.js +20 -0
- package/dist/src/render/widget-areas.js.map +1 -0
- package/dist/theme.config.d.ts +1 -1
- 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/blocks/accordion.ts +18 -47
- package/src/render/blocks/collection-list.ts +245 -133
- package/src/render/blocks/cta.ts +20 -11
- package/src/render/blocks/embed.ts +45 -36
- package/src/render/blocks/faq.ts +32 -25
- package/src/render/blocks/feature-grid.ts +83 -33
- package/src/render/blocks/gallery.ts +39 -21
- package/src/render/blocks/hero.ts +41 -34
- package/src/render/blocks/logo-strip.ts +27 -25
- package/src/render/blocks/logos.ts +34 -43
- package/src/render/blocks/media-figure.ts +49 -24
- package/src/render/blocks/pricing-table.ts +30 -42
- package/src/render/blocks/prose.ts +18 -9
- package/src/render/blocks/quote.ts +29 -19
- package/src/render/blocks/stat-counter.ts +24 -29
- package/src/render/blocks/stats.ts +30 -40
- package/src/render/blocks/testimonial.ts +17 -22
- package/src/render/chrome.ts +113 -95
- package/src/render/dish.ts +195 -0
- package/src/render/layout.ts +64 -0
- package/src/render/menu.ts +117 -0
- package/src/render/render-block.ts +51 -40
- package/src/render/strings.ts +44 -0
- package/src/render/term-archive.ts +78 -44
- package/src/render/widget-areas.ts +23 -0
- package/src/styles/archive.css +46 -56
- package/src/styles/base.css +807 -554
- package/src/styles/blocks.css +723 -641
- package/src/styles/menu.css +482 -0
- package/src/styles/theme.css +24 -25
- package/src/styles/tokens.css +239 -225
- package/src/styles/widgets.css +853 -0
- package/tokens.json +16 -16
package/src/render/blocks/faq.ts
CHANGED
|
@@ -1,53 +1,60 @@
|
|
|
1
1
|
import type { FaqBlock, FaqItem } from '@cogenta/blocks'
|
|
2
2
|
import {
|
|
3
|
-
blockHeadingTag,
|
|
4
3
|
type HtmlElement,
|
|
5
4
|
h,
|
|
6
|
-
|
|
5
|
+
nestedHeadingTag,
|
|
7
6
|
type RenderContext,
|
|
8
7
|
renderRichText,
|
|
9
8
|
} from '@cogenta/theme-kit'
|
|
9
|
+
import { section, sectionHead } from '../layout.js'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* Questions before a visit (a table for eight, a child's plate, a dog in the
|
|
13
|
+
* room), in two columns on a wide screen: the title on the first four, and
|
|
14
|
+
* the questions on the last eight, each under a hairline.
|
|
15
|
+
*
|
|
16
|
+
* Every answer is a `<details>`: it opens without a script and is found by
|
|
17
|
+
* the browser's own search. The question sits in a real heading inside the
|
|
18
|
+
* summary, so a screen reader's heading list still reaches every one of
|
|
19
|
+
* them. The plus that turns into a minus is two hairlines drawn by the
|
|
20
|
+
* stylesheet, not a glyph.
|
|
16
21
|
*/
|
|
17
|
-
function
|
|
18
|
-
|
|
22
|
+
export function answerItem(
|
|
23
|
+
item: FaqItem,
|
|
24
|
+
ctx: RenderContext,
|
|
25
|
+
blockName: 'faq' | 'accordion',
|
|
26
|
+
titled: boolean,
|
|
27
|
+
): HtmlElement {
|
|
19
28
|
return h(
|
|
20
29
|
'li',
|
|
21
|
-
{ class: '
|
|
30
|
+
{ class: 'cr-answers__item' },
|
|
22
31
|
h(
|
|
23
32
|
'details',
|
|
24
|
-
{ class: '
|
|
33
|
+
{ class: 'cr-answers__details' },
|
|
25
34
|
h(
|
|
26
35
|
'summary',
|
|
27
|
-
{ class: '
|
|
28
|
-
h(
|
|
29
|
-
h('span', { class: '
|
|
36
|
+
{ class: 'cr-answers__summary' },
|
|
37
|
+
h(nestedHeadingTag(blockName, titled), { class: 'cr-answers__question' }, item.question),
|
|
38
|
+
h('span', { class: 'cr-answers__mark', 'aria-hidden': 'true' }),
|
|
30
39
|
),
|
|
31
|
-
h('div', { class: '
|
|
40
|
+
h('div', { class: 'cr-answers__answer' }, renderRichText(ctx, item.answer)),
|
|
32
41
|
),
|
|
33
42
|
)
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
export function renderFaq(block: FaqBlock, ctx: RenderContext): HtmlElement {
|
|
37
|
-
|
|
46
|
+
const titled = block.title !== undefined
|
|
47
|
+
return section(
|
|
38
48
|
'section',
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{ class: 'cg-faq__title', 'data-field': 'title' },
|
|
45
|
-
block.title,
|
|
46
|
-
),
|
|
49
|
+
'faq',
|
|
50
|
+
'cr-answers',
|
|
51
|
+
{ 'data-titled': String(titled) },
|
|
52
|
+
'div',
|
|
53
|
+
sectionHead('faq', block.title),
|
|
47
54
|
h(
|
|
48
55
|
'ul',
|
|
49
|
-
{ class: '
|
|
50
|
-
block.items.map((item
|
|
56
|
+
{ class: 'cr-answers__items' },
|
|
57
|
+
block.items.map((item) => answerItem(item, ctx, 'faq', titled)),
|
|
51
58
|
),
|
|
52
59
|
)
|
|
53
60
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { FeatureGridBlock, FeatureItem } from '@cogenta/blocks'
|
|
2
2
|
import {
|
|
3
|
-
blockHeadingTag,
|
|
4
|
-
type HeadingTag,
|
|
5
3
|
type HtmlElement,
|
|
6
4
|
h,
|
|
7
5
|
heading,
|
|
@@ -10,52 +8,104 @@ import {
|
|
|
10
8
|
type RenderContext,
|
|
11
9
|
renderIcon,
|
|
12
10
|
} from '@cogenta/theme-kit'
|
|
11
|
+
import { section, sectionHead } from '../layout.js'
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* Two readings of the same block, chosen by its content rather than by a
|
|
15
|
+
* setting:
|
|
16
|
+
*
|
|
17
|
+
* - **A ruled table**, when no item names an icon. The items are facts a
|
|
18
|
+
* guest looks up (lunch, dinner, the address, the metro stop; a supplier
|
|
19
|
+
* and what they bring), so they are set like the back of a menu card: the
|
|
20
|
+
* title of the table on the first four columns, then one row per item under
|
|
21
|
+
* a hairline, its name in the serif on the left and its sentence on the
|
|
22
|
+
* right. A name with a link is an arrow link.
|
|
23
|
+
* - **Ruled columns**, when an item names an icon this theme can draw: a
|
|
24
|
+
* small line icon, the name, its sentence, each column under a hairline.
|
|
25
|
+
* Never a tinted tile behind an icon, never a card.
|
|
18
26
|
*/
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
function hasIcons(block: FeatureGridBlock): boolean {
|
|
28
|
+
return block.items.some((item) => item.icon !== undefined)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function name(item: FeatureItem, ctx: RenderContext, className: string): HtmlElement | string {
|
|
32
|
+
return item.link === undefined
|
|
33
|
+
? item.title
|
|
34
|
+
: h('a', { class: `cr-arrow-link ${className}`, href: href(ctx, item.link) }, item.title)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* In a table the link belongs to the value a guest acts on (the telephone
|
|
39
|
+
* number, the address), not to its label: "Telephone" is a heading, the
|
|
40
|
+
* number is what they tap. A row with no sentence links its label instead.
|
|
41
|
+
*/
|
|
42
|
+
function row(item: FeatureItem, ctx: RenderContext, titled: boolean): HtmlElement {
|
|
43
|
+
const label = heading(
|
|
44
|
+
nestedHeadingTag('featureGrid', titled),
|
|
45
|
+
{ class: 'cr-table__label' },
|
|
46
|
+
item.text === undefined ? name(item, ctx, 'cr-table__link') : item.title,
|
|
47
|
+
)
|
|
48
|
+
if (item.text === undefined) return h('li', { class: 'cr-table__row' }, label)
|
|
49
|
+
return h(
|
|
50
|
+
'li',
|
|
51
|
+
{ class: 'cr-table__row' },
|
|
52
|
+
label,
|
|
53
|
+
h(
|
|
54
|
+
'p',
|
|
55
|
+
{ class: 'cr-table__text' },
|
|
56
|
+
item.link === undefined
|
|
57
|
+
? item.text
|
|
58
|
+
: h('a', { class: 'cr-table__value-link', href: href(ctx, item.link) }, item.text),
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function column(item: FeatureItem, ctx: RenderContext, titled: boolean): HtmlElement {
|
|
28
64
|
const icon =
|
|
29
65
|
item.icon === undefined
|
|
30
66
|
? null
|
|
31
|
-
:
|
|
32
|
-
h('span', { class: 'cg-craft__mark-fallback', 'data-icon': item.icon }))
|
|
67
|
+
: renderIcon(item.icon, { className: 'cr-columns__icon', size: 22 })
|
|
33
68
|
return h(
|
|
34
69
|
'li',
|
|
35
|
-
{ class: '
|
|
36
|
-
icon
|
|
37
|
-
|
|
38
|
-
|
|
70
|
+
{ class: 'cr-columns__item' },
|
|
71
|
+
icon,
|
|
72
|
+
heading(
|
|
73
|
+
nestedHeadingTag('featureGrid', titled),
|
|
74
|
+
{ class: 'cr-columns__name' },
|
|
75
|
+
name(item, ctx, 'cr-columns__link'),
|
|
76
|
+
),
|
|
77
|
+
item.text === undefined ? null : h('p', { class: 'cr-columns__text' }, item.text),
|
|
39
78
|
)
|
|
40
79
|
}
|
|
41
80
|
|
|
42
81
|
export function renderFeatureGrid(block: FeatureGridBlock, ctx: RenderContext): HtmlElement {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
82
|
+
const titled = block.title !== undefined
|
|
83
|
+
if (!hasIcons(block)) {
|
|
84
|
+
return section(
|
|
85
|
+
'section',
|
|
86
|
+
'featureGrid',
|
|
87
|
+
'cr-table',
|
|
88
|
+
{ 'data-titled': String(titled) },
|
|
89
|
+
'div',
|
|
90
|
+
sectionHead('featureGrid', block.title),
|
|
91
|
+
h(
|
|
92
|
+
'ul',
|
|
93
|
+
{ class: 'cr-table__rows' },
|
|
94
|
+
block.items.map((item) => row(item, ctx, titled)),
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
return section(
|
|
46
99
|
'section',
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
block.title ?? '',
|
|
53
|
-
)
|
|
54
|
-
: null,
|
|
100
|
+
'featureGrid',
|
|
101
|
+
'cr-columns',
|
|
102
|
+
{ 'data-titled': String(titled), 'data-count': String(Math.min(block.items.length, 4)) },
|
|
103
|
+
'div',
|
|
104
|
+
sectionHead('featureGrid', block.title),
|
|
55
105
|
h(
|
|
56
106
|
'ul',
|
|
57
|
-
{ class: '
|
|
58
|
-
block.items.map((item) =>
|
|
107
|
+
{ class: 'cr-columns__items' },
|
|
108
|
+
block.items.map((item) => column(item, ctx, titled)),
|
|
59
109
|
),
|
|
60
110
|
)
|
|
61
111
|
}
|
|
@@ -1,40 +1,58 @@
|
|
|
1
1
|
import type { GalleryBlock } from '@cogenta/blocks'
|
|
2
2
|
import { type HtmlElement, h, image, type RenderContext } from '@cogenta/theme-kit'
|
|
3
|
+
import { section } from '../layout.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* a
|
|
9
|
-
*
|
|
6
|
+
* Photographs of plates and of the room, in the three layouts contract B
|
|
7
|
+
* names:
|
|
8
|
+
*
|
|
9
|
+
* - `grid`: a band of dish photographs, every one cropped to the same 4:5
|
|
10
|
+
* portrait, four across on a wide screen (three when the count divides by
|
|
11
|
+
* three, so a row is never left with one picture), two on a phone.
|
|
12
|
+
* - `masonry`: three columns of pictures at their own proportions.
|
|
13
|
+
* - `carousel`: a row of 4:5 crops that scrolls sideways, with native scroll
|
|
14
|
+
* snapping. It is a focusable, labelled region so the row can be scrolled
|
|
15
|
+
* from the keyboard; no script drives it.
|
|
10
16
|
*/
|
|
17
|
+
function columnsFor(count: number): number {
|
|
18
|
+
if (count <= 2) return count
|
|
19
|
+
return count % 3 === 0 ? 3 : 4
|
|
20
|
+
}
|
|
21
|
+
|
|
11
22
|
export function renderGallery(block: GalleryBlock, ctx: RenderContext): HtmlElement {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
const carousel = block.layout === 'carousel'
|
|
24
|
+
const columns = columnsFor(block.items.length)
|
|
25
|
+
const items = block.items.map((item) =>
|
|
26
|
+
h(
|
|
27
|
+
'li',
|
|
28
|
+
{ class: 'cr-gallery__item' },
|
|
29
|
+
image(ctx, item.media, {
|
|
30
|
+
className: 'cr-gallery__image',
|
|
31
|
+
sizes:
|
|
32
|
+
block.layout === 'grid'
|
|
33
|
+
? `(min-width: 64rem) ${Math.round(90 / Math.max(columns, 1))}vw, 50vw`
|
|
34
|
+
: '(min-width: 64rem) 30vw, 80vw',
|
|
35
|
+
}),
|
|
21
36
|
),
|
|
22
37
|
)
|
|
23
38
|
|
|
24
|
-
return
|
|
25
|
-
'
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
return section(
|
|
40
|
+
'div',
|
|
41
|
+
'gallery',
|
|
42
|
+
'cr-gallery',
|
|
43
|
+
{ 'data-layout': block.layout, 'data-columns': String(columns) },
|
|
44
|
+
'div',
|
|
45
|
+
carousel
|
|
28
46
|
? h(
|
|
29
47
|
'div',
|
|
30
48
|
{
|
|
31
|
-
class: '
|
|
49
|
+
class: 'cr-gallery__viewport',
|
|
32
50
|
role: 'region',
|
|
33
51
|
'aria-label': ctx.t('gallery.carousel'),
|
|
34
52
|
tabindex: '0',
|
|
35
53
|
},
|
|
36
|
-
items,
|
|
54
|
+
h('ul', { class: 'cr-gallery__items' }, items),
|
|
37
55
|
)
|
|
38
|
-
: items,
|
|
56
|
+
: h('ul', { class: 'cr-gallery__items' }, items),
|
|
39
57
|
)
|
|
40
58
|
}
|
|
@@ -1,58 +1,65 @@
|
|
|
1
1
|
import type { HeroBlock } from '@cogenta/blocks'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
blockHeadingTag,
|
|
5
|
-
type HtmlElement,
|
|
6
|
-
h,
|
|
7
|
-
heading,
|
|
8
|
-
image,
|
|
9
|
-
type RenderContext,
|
|
10
|
-
} from '@cogenta/theme-kit'
|
|
2
|
+
import { actionList, type HtmlElement, h, image, type RenderContext } from '@cogenta/theme-kit'
|
|
3
|
+
import { optionalText } from '../layout.js'
|
|
11
4
|
|
|
12
5
|
/**
|
|
13
|
-
* The
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* centred — the "elegant restaurant homepage" convention (Divi/Astra
|
|
17
|
-
* "Restaurant") rather than the left-aligned marketing hero the other
|
|
18
|
-
* built-in themes use.
|
|
6
|
+
* The opening of a page: the photograph of the room across the whole width
|
|
7
|
+
* of the window, then the name of the place set large and light in the
|
|
8
|
+
* display serif, on the page's own ground.
|
|
19
9
|
*
|
|
20
|
-
* The
|
|
21
|
-
*
|
|
22
|
-
*
|
|
10
|
+
* The words sit under the picture, never on it. A headline laid over a
|
|
11
|
+
* photograph needs a veil to stay legible on every picture an editor may
|
|
12
|
+
* choose, and a veil over a dining room is exactly what makes it look like
|
|
13
|
+
* every other restaurant template; set on the paper, the name is legible in
|
|
14
|
+
* both schemes whatever the photograph, and the room stays as it was lit.
|
|
15
|
+
*
|
|
16
|
+
* Name on the first eight columns, its baseline shared with the subtitle and
|
|
17
|
+
* the action on the last four. An eyebrow, when there is one, is a line of
|
|
18
|
+
* small capitals above the name, never a badge. Without media the block is
|
|
19
|
+
* the name row alone.
|
|
20
|
+
*
|
|
21
|
+
* The image is the only one on a page loaded eagerly: it is above the fold
|
|
22
|
+
* by construction.
|
|
23
23
|
*/
|
|
24
24
|
export function renderHero(block: HeroBlock, ctx: RenderContext): HtmlElement {
|
|
25
|
-
const
|
|
25
|
+
const actions = actionList(ctx, block.actions, ctx.t('hero.actions'))
|
|
26
|
+
const hasAside = block.subtitle !== undefined || actions !== null
|
|
27
|
+
|
|
26
28
|
return h(
|
|
27
29
|
'section',
|
|
28
30
|
{
|
|
29
|
-
class: '
|
|
31
|
+
class: 'cr-section cr-hero',
|
|
30
32
|
'data-block': 'hero',
|
|
31
|
-
'data-
|
|
33
|
+
'data-media': block.media === undefined ? 'false' : 'true',
|
|
32
34
|
},
|
|
33
35
|
block.media === undefined
|
|
34
36
|
? null
|
|
35
37
|
: h(
|
|
36
|
-
'
|
|
37
|
-
{ class: '
|
|
38
|
+
'figure',
|
|
39
|
+
{ class: 'cr-hero__media' },
|
|
38
40
|
image(ctx, block.media, {
|
|
39
|
-
className: '
|
|
41
|
+
className: 'cr-hero__image',
|
|
40
42
|
loading: 'eager',
|
|
41
43
|
sizes: '100vw',
|
|
42
44
|
}),
|
|
43
|
-
h('div', { class: 'cg-hero__scrim', 'aria-hidden': 'true' }),
|
|
44
45
|
),
|
|
45
46
|
h(
|
|
46
47
|
'div',
|
|
47
|
-
{ class: '
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
{ class: 'cr-container cr-hero__inner' },
|
|
49
|
+
h(
|
|
50
|
+
'div',
|
|
51
|
+
{ class: 'cr-hero__heading' },
|
|
52
|
+
optionalText('p', 'cr-hero__eyebrow', block.eyebrow, { 'data-field': 'eyebrow' }),
|
|
53
|
+
h('h1', { class: 'cr-hero__title', 'data-field': 'title' }, block.title),
|
|
54
|
+
),
|
|
55
|
+
hasAside
|
|
56
|
+
? h(
|
|
57
|
+
'div',
|
|
58
|
+
{ class: 'cr-hero__aside' },
|
|
59
|
+
optionalText('p', 'cr-hero__subtitle', block.subtitle, { 'data-field': 'subtitle' }),
|
|
60
|
+
actions,
|
|
61
|
+
)
|
|
62
|
+
: null,
|
|
56
63
|
),
|
|
57
64
|
)
|
|
58
65
|
}
|
|
@@ -1,35 +1,37 @@
|
|
|
1
|
-
import type { LogoStripBlock
|
|
1
|
+
import type { LogoStripBlock } from '@cogenta/blocks'
|
|
2
2
|
import { type HtmlElement, h, image, type RenderContext } from '@cogenta/theme-kit'
|
|
3
|
+
import { section } from '../layout.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The lighter row of marks: the caption at the caption size on the first
|
|
7
|
+
* three columns, the marks spread along one line across the rest, small and
|
|
8
|
+
* evenly spaced. No links, by contract B; each mark is named by its own alt
|
|
9
|
+
* text from the media library.
|
|
9
10
|
*/
|
|
10
|
-
function renderItem(item: LogoStripItem, ctx: RenderContext): HtmlElement {
|
|
11
|
-
return h(
|
|
12
|
-
'li',
|
|
13
|
-
{ class: 'cg-press-strip__item' },
|
|
14
|
-
image(ctx, item.media, { className: 'cg-press-strip__image', variant: { fit: 'contain' } }),
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
11
|
export function renderLogoStrip(block: LogoStripBlock, ctx: RenderContext): HtmlElement {
|
|
19
|
-
return
|
|
20
|
-
'
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
block.logos.map((item) => renderItem(item, ctx)),
|
|
26
|
-
),
|
|
12
|
+
return section(
|
|
13
|
+
'div',
|
|
14
|
+
'logoStrip',
|
|
15
|
+
'cr-strip',
|
|
16
|
+
{ 'data-captioned': String(block.caption !== undefined) },
|
|
17
|
+
'div',
|
|
27
18
|
block.caption === undefined
|
|
28
19
|
? null
|
|
29
|
-
: h(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
: h('p', { class: 'cr-strip__caption', 'data-field': 'caption' }, block.caption),
|
|
21
|
+
h(
|
|
22
|
+
'ul',
|
|
23
|
+
{ class: 'cr-strip__items' },
|
|
24
|
+
block.logos.map((logo) =>
|
|
25
|
+
h(
|
|
26
|
+
'li',
|
|
27
|
+
{ class: 'cr-strip__item' },
|
|
28
|
+
h(
|
|
29
|
+
'span',
|
|
30
|
+
{ class: 'cr-marks__plate' },
|
|
31
|
+
image(ctx, logo.media, { className: 'cr-marks__image', sizes: '10rem' }),
|
|
32
|
+
),
|
|
33
33
|
),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
34
36
|
)
|
|
35
37
|
}
|
|
@@ -1,53 +1,44 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
type HtmlElement,
|
|
5
|
-
h,
|
|
6
|
-
heading,
|
|
7
|
-
image,
|
|
8
|
-
type RenderContext,
|
|
9
|
-
} from '@cogenta/theme-kit'
|
|
1
|
+
import type { LogosBlock } from '@cogenta/blocks'
|
|
2
|
+
import { type HtmlElement, h, image, type RenderContext } from '@cogenta/theme-kit'
|
|
3
|
+
import { section, sectionHead } from '../layout.js'
|
|
10
4
|
|
|
11
5
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
6
|
+
* Guides, publications, the growers' cooperative: their marks along one
|
|
7
|
+
* ruled row, each set small and in its own colours. A mark drawn for paper
|
|
8
|
+
* sits on a pale plate in the dark scheme so it never disappears.
|
|
9
|
+
*
|
|
10
|
+
* The organisation's name is the mark's accessible name when the media
|
|
11
|
+
* library has no alt text for it, and the link's own name when it links out.
|
|
16
12
|
*/
|
|
17
|
-
function renderItem(item: LogoItem, ctx: RenderContext): HtmlElement {
|
|
18
|
-
const logo = image(ctx, item.media, {
|
|
19
|
-
className: 'cg-press__logo',
|
|
20
|
-
altFrom: item.name,
|
|
21
|
-
variant: { fit: 'contain' },
|
|
22
|
-
})
|
|
23
|
-
return h(
|
|
24
|
-
'li',
|
|
25
|
-
{ class: 'cg-press__item' },
|
|
26
|
-
item.url === undefined
|
|
27
|
-
? logo
|
|
28
|
-
: h(
|
|
29
|
-
'a',
|
|
30
|
-
{ class: 'cg-press__link', href: ctx.link(item.url), rel: 'noopener noreferrer' },
|
|
31
|
-
logo,
|
|
32
|
-
),
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
13
|
export function renderLogos(block: LogosBlock, ctx: RenderContext): HtmlElement {
|
|
37
|
-
return
|
|
14
|
+
return section(
|
|
38
15
|
'section',
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{ class: 'cg-press__title', 'data-field': 'title' },
|
|
45
|
-
block.title,
|
|
46
|
-
),
|
|
16
|
+
'logos',
|
|
17
|
+
'cr-marks',
|
|
18
|
+
{},
|
|
19
|
+
'div',
|
|
20
|
+
sectionHead('logos', block.title),
|
|
47
21
|
h(
|
|
48
22
|
'ul',
|
|
49
|
-
{ class: '
|
|
50
|
-
block.items.map((item) =>
|
|
23
|
+
{ class: 'cr-marks__items' },
|
|
24
|
+
block.items.map((item) => {
|
|
25
|
+
const mark = image(ctx, item.media, {
|
|
26
|
+
className: 'cr-marks__image',
|
|
27
|
+
altFrom: item.name,
|
|
28
|
+
sizes: '10rem',
|
|
29
|
+
})
|
|
30
|
+
return h(
|
|
31
|
+
'li',
|
|
32
|
+
{ class: 'cr-marks__item' },
|
|
33
|
+
item.url === undefined
|
|
34
|
+
? h('span', { class: 'cr-marks__plate' }, mark)
|
|
35
|
+
: h(
|
|
36
|
+
'a',
|
|
37
|
+
{ class: 'cr-marks__plate', href: item.url, rel: 'noopener noreferrer' },
|
|
38
|
+
mark,
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
}),
|
|
51
42
|
),
|
|
52
43
|
)
|
|
53
44
|
}
|
|
@@ -1,39 +1,64 @@
|
|
|
1
1
|
import type { MediaFigureBlock } from '@cogenta/blocks'
|
|
2
2
|
import { aspectRatio, type HtmlElement, h, image, type RenderContext } from '@cogenta/theme-kit'
|
|
3
|
+
import { section } from '../layout.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* A
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* A photograph and its caption.
|
|
7
|
+
*
|
|
8
|
+
* `align` is an editorial intent, read as a layout:
|
|
9
|
+
*
|
|
10
|
+
* - `start` / `end`: the room-and-story split. The photograph takes seven
|
|
11
|
+
* columns on its side and the caption, set in the serif italic at the lead
|
|
12
|
+
* size, takes the other four, so a caption reads as a line from the house
|
|
13
|
+
* beside the picture.
|
|
14
|
+
* - `center`: eight columns, set in from the left edge.
|
|
15
|
+
* - `wide` (and no value): the whole container.
|
|
16
|
+
* - `full`: the whole window, edge to edge.
|
|
17
|
+
*
|
|
18
|
+
* The ratio crops from the middle, or from the media's own focal point; the
|
|
19
|
+
* corners stay square and the picture casts no shadow.
|
|
8
20
|
*/
|
|
9
21
|
export function renderMediaFigure(block: MediaFigureBlock, ctx: RenderContext): HtmlElement {
|
|
22
|
+
const align = block.align ?? 'wide'
|
|
23
|
+
const split = align === 'start' || align === 'end'
|
|
10
24
|
const ratio = aspectRatio(block.ratio)
|
|
11
|
-
|
|
12
|
-
|
|
25
|
+
|
|
26
|
+
const caption =
|
|
27
|
+
block.caption === undefined && block.credit === undefined
|
|
28
|
+
? null
|
|
29
|
+
: h(
|
|
30
|
+
'figcaption',
|
|
31
|
+
{ class: 'cr-figure__caption' },
|
|
32
|
+
block.caption === undefined
|
|
33
|
+
? null
|
|
34
|
+
: h('span', { class: 'cr-figure__text', 'data-field': 'caption' }, block.caption),
|
|
35
|
+
block.credit === undefined
|
|
36
|
+
? null
|
|
37
|
+
: h('span', { class: 'cr-figure__credit', 'data-field': 'credit' }, block.credit),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return section(
|
|
41
|
+
'div',
|
|
42
|
+
'mediaFigure',
|
|
43
|
+
'cr-figure',
|
|
44
|
+
{ 'data-align': align, 'data-layout': split ? 'split' : 'single' },
|
|
13
45
|
'figure',
|
|
14
|
-
{
|
|
15
|
-
class: 'cg-plate',
|
|
16
|
-
'data-block': 'mediaFigure',
|
|
17
|
-
'data-align': block.align ?? 'center',
|
|
18
|
-
style: ratio === undefined ? undefined : `--cg-ratio:${ratio}`,
|
|
19
|
-
},
|
|
20
46
|
h(
|
|
21
47
|
'div',
|
|
22
|
-
{
|
|
48
|
+
{
|
|
49
|
+
class: 'cr-figure__frame',
|
|
50
|
+
style: ratio === undefined ? undefined : `aspect-ratio:${ratio}`,
|
|
51
|
+
},
|
|
23
52
|
image(ctx, block.media, {
|
|
24
|
-
className: '
|
|
25
|
-
sizes:
|
|
53
|
+
className: 'cr-figure__image',
|
|
54
|
+
sizes:
|
|
55
|
+
align === 'full'
|
|
56
|
+
? '100vw'
|
|
57
|
+
: split
|
|
58
|
+
? '(min-width: 64rem) 55vw, 100vw'
|
|
59
|
+
: '(min-width: 90rem) 86rem, 100vw',
|
|
26
60
|
}),
|
|
27
61
|
),
|
|
28
|
-
|
|
29
|
-
? h(
|
|
30
|
-
'figcaption',
|
|
31
|
-
{ class: 'cg-plate__caption' },
|
|
32
|
-
block.caption,
|
|
33
|
-
block.credit === undefined
|
|
34
|
-
? null
|
|
35
|
-
: h('span', { class: 'cg-plate__credit', 'data-field': 'credit' }, block.credit),
|
|
36
|
-
)
|
|
37
|
-
: null,
|
|
62
|
+
caption,
|
|
38
63
|
)
|
|
39
64
|
}
|