@cogenta/theme-restaurant 0.3.3 → 0.5.4
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 +803 -550
- 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
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
h,
|
|
6
6
|
type PageContent,
|
|
7
7
|
pageHasOwnHeading,
|
|
8
|
+
providedBlockNode,
|
|
8
9
|
type RenderContext,
|
|
9
|
-
renderEntryHeader,
|
|
10
10
|
resolveBlockForRender,
|
|
11
11
|
withBlockKey,
|
|
12
12
|
withBlockVariant,
|
|
@@ -28,6 +28,7 @@ import { renderQuote } from './blocks/quote.js'
|
|
|
28
28
|
import { renderStatCounter } from './blocks/stat-counter.js'
|
|
29
29
|
import { renderStats } from './blocks/stats.js'
|
|
30
30
|
import { renderTestimonial } from './blocks/testimonial.js'
|
|
31
|
+
import { isDishPage, renderDishHeader, renderPageHeader } from './dish.js'
|
|
31
32
|
|
|
32
33
|
export type { FetchedEntries, PageContent }
|
|
33
34
|
|
|
@@ -37,13 +38,19 @@ export function renderBlock(
|
|
|
37
38
|
entries: FetchedEntries = {},
|
|
38
39
|
registry?: BlockRegistry,
|
|
39
40
|
): HtmlElement | null {
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
41
|
+
// A block a plugin provides arrives already rendered by the host, in a
|
|
42
|
+
// process of its own (contract D theme@1.7). Nothing else in this theme
|
|
43
|
+
// needs to know such blocks exist.
|
|
44
|
+
const provided = providedBlockNode(block, ctx)
|
|
45
|
+
if (provided !== null) return withBlockVariant(provided, block.variant)
|
|
46
|
+
// A stored block is not always literally one of the shared vocabulary:
|
|
47
|
+
// resolving here turns an unimplemented theme-private block into its
|
|
48
|
+
// declared fallback instead of a silently blank slot.
|
|
44
49
|
const resolved = resolveBlockForRender(block, VOCABULARY_NAMES, registry)
|
|
45
50
|
if (resolved === null) return null
|
|
46
51
|
const known = resolved as unknown as VocabularyBlock
|
|
52
|
+
// `variant` is envelope data every block carries identically, applied once
|
|
53
|
+
// here rather than by each of the seventeen renderers.
|
|
47
54
|
return withBlockVariant(renderKnownBlock(known, ctx, entries), known.variant)
|
|
48
55
|
}
|
|
49
56
|
|
|
@@ -88,9 +95,9 @@ function renderKnownBlock(
|
|
|
88
95
|
case 'logoStrip':
|
|
89
96
|
return renderLogoStrip(known, ctx)
|
|
90
97
|
default: {
|
|
91
|
-
// Exhaustive over contract B
|
|
92
|
-
//
|
|
93
|
-
// is.
|
|
98
|
+
// Exhaustive over contract B: `known` is `never` here, so a block this
|
|
99
|
+
// package does not implement stops it compiling until it is. `null`
|
|
100
|
+
// rather than a throw: choosing a fallback is the render layer's job.
|
|
94
101
|
const unreachable: never = known
|
|
95
102
|
void unreachable
|
|
96
103
|
return null
|
|
@@ -99,53 +106,57 @@ function renderKnownBlock(
|
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* `
|
|
106
|
-
*
|
|
107
|
-
* the rendered iframe back to the block that produced it.
|
|
108
|
-
*
|
|
109
|
-
* A routed collection with no `blocks` field of its own — this theme's
|
|
110
|
-
* `menu_item`, in particular — reaches here with an empty block list, so
|
|
111
|
-
* `page.entry` (contract D `theme@1.4`) is what carries its furniture:
|
|
112
|
-
* `renderEntryHeader` draws the title, excerpt (the dish's own
|
|
113
|
-
* `description`, via `entryExcerpt`'s field-name convention) and cover
|
|
114
|
-
* photo. `PageEntryMeta` has no room for a schema-specific field such as
|
|
115
|
-
* `price`/`category`, so a menu item's own page cannot show them without a
|
|
116
|
-
* contract D change — the theme's real, honest limit; the price and
|
|
117
|
-
* category chip the brief also asks for are exactly what the home page's
|
|
118
|
-
* `collectionList` menu already renders for every dish, and the item page
|
|
119
|
-
* still links back there.
|
|
120
|
-
*/
|
|
121
|
-
/**
|
|
122
|
-
* A second, theme-local stamp beside `withBlockKey`'s own `data-block-key`:
|
|
123
|
-
* a real `id` attribute, so this theme's single-page navigation (the
|
|
124
|
-
* blueprint's header/footer links into `#home-menu`/`#home-story`/etc.) has
|
|
125
|
-
* something to scroll to. Contract B's `_key` is already guaranteed unique
|
|
126
|
-
* within one page's block list (the reorder/diff identity every block
|
|
127
|
-
* carries), so reusing it as the DOM id can never collide on a page this
|
|
128
|
-
* theme rendered — safe to do generically, for every block, not only the
|
|
129
|
-
* ones a blueprint happens to link to.
|
|
109
|
+
* A real `id` beside `withBlockKey`'s `data-block-key`, so a menu link to
|
|
110
|
+
* `/#<key>` still has somewhere to land: sites built on this theme before its
|
|
111
|
+
* multi-page blueprint linked their header straight into home page blocks.
|
|
112
|
+
* Contract B's `_key` is unique within one page's block list, so it can never
|
|
113
|
+
* collide on a page this theme rendered.
|
|
130
114
|
*/
|
|
131
115
|
function withAnchorId(element: HtmlElement | null, key: string): HtmlElement | null {
|
|
132
116
|
if (element === null) return null
|
|
133
117
|
return { ...element, attrs: { ...element.attrs, id: key } }
|
|
134
118
|
}
|
|
135
119
|
|
|
120
|
+
/**
|
|
121
|
+
* `<main id="cg-main">` is mandatory: it is the skip link's target, written
|
|
122
|
+
* by the host outside any theme's control.
|
|
123
|
+
*
|
|
124
|
+
* Three openings, and exactly one `h1` in each:
|
|
125
|
+
*
|
|
126
|
+
* - a page whose blocks include a `hero` lets the hero carry the title;
|
|
127
|
+
* - a dish (`isDishPage`: its `theme@1.5` fields carry a price) gets the dish
|
|
128
|
+
* sheet: photograph, section, name, description, price, details;
|
|
129
|
+
* - anything else gets its title set large on the grid.
|
|
130
|
+
*
|
|
131
|
+
* A host older than `theme@1.5` sends no fields, so its dish pages open like
|
|
132
|
+
* any other page: title and description, never a price read from somewhere
|
|
133
|
+
* it was not given. A host older than `theme@1.4` sends no entry at all, and
|
|
134
|
+
* the page opens on its bare title.
|
|
135
|
+
*
|
|
136
|
+
* `withBlockKey` stamps every rendered block with its contract-B `_key`, so
|
|
137
|
+
* the visual page builder (L16) can map a clicked element back to its block.
|
|
138
|
+
*/
|
|
136
139
|
export function renderPage(
|
|
137
140
|
page: PageContent,
|
|
138
141
|
ctx: RenderContext,
|
|
139
142
|
entries: FetchedEntries = {},
|
|
140
143
|
registry?: BlockRegistry,
|
|
141
144
|
): HtmlElement {
|
|
142
|
-
const
|
|
145
|
+
const ownHeading = pageHasOwnHeading(page.blocks)
|
|
146
|
+
const dish = !ownHeading && isDishPage(page.entry) ? page.entry : undefined
|
|
147
|
+
const opening = ownHeading
|
|
143
148
|
? null
|
|
144
|
-
:
|
|
149
|
+
: dish !== undefined
|
|
150
|
+
? renderDishHeader(page, dish, ctx)
|
|
151
|
+
: renderPageHeader(page, ctx)
|
|
152
|
+
|
|
145
153
|
return h(
|
|
146
154
|
'main',
|
|
147
|
-
{
|
|
148
|
-
|
|
155
|
+
{
|
|
156
|
+
class: dish === undefined ? 'cg-main cr-main' : 'cg-main cr-main cr-main--dish',
|
|
157
|
+
id: 'cg-main',
|
|
158
|
+
},
|
|
159
|
+
opening,
|
|
149
160
|
page.blocks.map((block) =>
|
|
150
161
|
withAnchorId(
|
|
151
162
|
withBlockKey(renderBlock(block, ctx, entries, registry), block._key),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { interpolate, themeLocaleFor } from '@cogenta/theme-kit'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The few words a restaurant's own pages need that the shared vocabulary
|
|
5
|
+
* does not: the labels of a dish's details, and the word a menu prints beside
|
|
6
|
+
* a vegetarian dish.
|
|
7
|
+
*
|
|
8
|
+
* `@cogenta/theme-kit`'s `THEME_STRINGS` carries the dozen strings every
|
|
9
|
+
* theme's blocks share; these belong to one register (a menu and a dish
|
|
10
|
+
* page), so they live with the theme that draws them, in the two languages
|
|
11
|
+
* the shared table knows. A locale the table does not know reads English, the
|
|
12
|
+
* same rule `createThemeTranslator` follows.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
type MenuStringKey = 'price' | 'vegetarian' | 'details' | 'sourcing' | 'allergens' | 'pairing'
|
|
16
|
+
|
|
17
|
+
const STRINGS: Readonly<Record<'en' | 'fr', Readonly<Record<MenuStringKey, string>>>> = {
|
|
18
|
+
en: {
|
|
19
|
+
price: 'Price',
|
|
20
|
+
vegetarian: 'Vegetarian',
|
|
21
|
+
details: 'About the dish',
|
|
22
|
+
sourcing: 'From',
|
|
23
|
+
allergens: 'Allergens',
|
|
24
|
+
pairing: 'To drink',
|
|
25
|
+
},
|
|
26
|
+
fr: {
|
|
27
|
+
price: 'Prix',
|
|
28
|
+
vegetarian: 'Végétarien',
|
|
29
|
+
details: 'À propos du plat',
|
|
30
|
+
sourcing: 'Provenance',
|
|
31
|
+
allergens: 'Allergènes',
|
|
32
|
+
pairing: 'À boire',
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function menuString(
|
|
37
|
+
locale: string,
|
|
38
|
+
key: MenuStringKey,
|
|
39
|
+
values?: Readonly<Record<string, string | number>>,
|
|
40
|
+
): string {
|
|
41
|
+
return interpolate(STRINGS[themeLocaleFor(locale)][key], values)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type { MenuStringKey }
|
|
@@ -1,65 +1,86 @@
|
|
|
1
1
|
import { type HtmlElement, h, type TermArchiveInput } from '@cogenta/theme-kit'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The taxonomy-term archive (contract D `theme@1.3`)
|
|
4
|
+
* The taxonomy-term archive (contract D `theme@1.3`), set in the dining
|
|
5
|
+
* room's own register: a breadcrumb in small words, the term as the page
|
|
6
|
+
* title in the display serif, its sub-terms as a ruled line of links, then
|
|
7
|
+
* the classified entries as ruled rows of titles and summaries, and a pager
|
|
8
|
+
* of two arrow links.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
10
|
+
* `TermArchiveEntry` carries no picture and no price, so an archive cannot be
|
|
11
|
+
* a menu or a band of plates; it is an index, drawn like one, rather than a
|
|
12
|
+
* menu of dishes with their prices missing. A restaurant that wants a priced
|
|
13
|
+
* section of its menu on a page of its own builds it from a
|
|
14
|
+
* `collectionList`, which carries both.
|
|
9
15
|
*/
|
|
10
16
|
export function renderTermArchive(input: TermArchiveInput): HtmlElement {
|
|
11
17
|
const rows = input.entries.map((entry) =>
|
|
12
18
|
h(
|
|
13
19
|
'li',
|
|
14
|
-
{ class: '
|
|
15
|
-
entry.publishedAt === null
|
|
16
|
-
? null
|
|
17
|
-
: h(
|
|
18
|
-
'time',
|
|
19
|
-
{ class: 'cg-index__date', datetime: entry.publishedAt },
|
|
20
|
-
entry.publishedAt.slice(0, 10),
|
|
21
|
-
),
|
|
20
|
+
{ class: 'cr-index__item' },
|
|
22
21
|
h(
|
|
23
|
-
'
|
|
24
|
-
{ class: '
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{ class: '
|
|
28
|
-
entry.href === null
|
|
29
|
-
? entry.title
|
|
30
|
-
: h('a', { class: 'cg-index__link', href: entry.href }, entry.title),
|
|
31
|
-
),
|
|
32
|
-
entry.summary === null ? null : h('p', { class: 'cg-index__excerpt' }, entry.summary),
|
|
22
|
+
'h2',
|
|
23
|
+
{ class: 'cr-index__name' },
|
|
24
|
+
entry.href === null
|
|
25
|
+
? entry.title
|
|
26
|
+
: h('a', { class: 'cr-index__link', href: entry.href }, entry.title),
|
|
33
27
|
),
|
|
28
|
+
entry.summary === null ? null : h('p', { class: 'cr-index__text' }, entry.summary),
|
|
34
29
|
),
|
|
35
30
|
)
|
|
36
31
|
|
|
37
32
|
return h(
|
|
38
33
|
'main',
|
|
39
|
-
{ class: 'cg-main
|
|
40
|
-
|
|
34
|
+
{ class: 'cg-main cr-main cr-archive', id: 'cg-main' },
|
|
35
|
+
h(
|
|
36
|
+
'header',
|
|
37
|
+
{ class: 'cr-page-head' },
|
|
38
|
+
h(
|
|
39
|
+
'div',
|
|
40
|
+
{ class: 'cr-container cr-page-head__inner' },
|
|
41
|
+
input.ancestors.length === 0
|
|
42
|
+
? null
|
|
43
|
+
: h(
|
|
44
|
+
'nav',
|
|
45
|
+
{ class: 'cr-archive__breadcrumb', 'aria-label': input.labels.breadcrumb },
|
|
46
|
+
h(
|
|
47
|
+
'ol',
|
|
48
|
+
{ class: 'cr-archive__trail' },
|
|
49
|
+
input.ancestors.map((link) => h('li', {}, h('a', { href: link.href }, link.label))),
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
h('h1', { class: 'cr-page-head__title' }, input.term.label),
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
input.children.length === 0
|
|
41
56
|
? null
|
|
42
57
|
: h(
|
|
43
|
-
'
|
|
44
|
-
{ class: '
|
|
58
|
+
'div',
|
|
59
|
+
{ class: 'cr-section cr-archive__children' },
|
|
45
60
|
h(
|
|
46
|
-
'
|
|
47
|
-
{},
|
|
48
|
-
|
|
61
|
+
'div',
|
|
62
|
+
{ class: 'cr-container' },
|
|
63
|
+
h(
|
|
64
|
+
'ul',
|
|
65
|
+
{ class: 'cr-archive__terms', 'aria-label': input.labels.subterms },
|
|
66
|
+
input.children.map((child) =>
|
|
67
|
+
h('li', { class: 'cr-archive__term' }, h('a', { href: child.href }, child.label)),
|
|
68
|
+
),
|
|
69
|
+
),
|
|
49
70
|
),
|
|
50
71
|
),
|
|
51
|
-
h(
|
|
52
|
-
|
|
53
|
-
?
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
h(
|
|
73
|
+
'section',
|
|
74
|
+
{ class: 'cr-section cr-list', 'data-shape': rows.length === 0 ? 'empty' : 'index' },
|
|
75
|
+
h(
|
|
76
|
+
'div',
|
|
77
|
+
{ class: 'cr-container cr-list__inner' },
|
|
78
|
+
rows.length === 0
|
|
79
|
+
? h('p', { class: 'cr-empty' }, input.labels.empty)
|
|
80
|
+
: h('ul', { class: 'cr-list__items cr-index' }, rows),
|
|
81
|
+
pager(input),
|
|
82
|
+
),
|
|
83
|
+
),
|
|
63
84
|
)
|
|
64
85
|
}
|
|
65
86
|
|
|
@@ -67,12 +88,25 @@ function pager(input: TermArchiveInput): HtmlElement | null {
|
|
|
67
88
|
if (input.page.previousHref === null && input.page.nextHref === null) return null
|
|
68
89
|
return h(
|
|
69
90
|
'nav',
|
|
70
|
-
{ class: '
|
|
91
|
+
{ class: 'cr-archive__pager', 'aria-label': input.labels.pagination },
|
|
71
92
|
input.page.previousHref === null
|
|
72
93
|
? null
|
|
73
|
-
: h(
|
|
94
|
+
: h(
|
|
95
|
+
'a',
|
|
96
|
+
{
|
|
97
|
+
class: 'cr-arrow-link',
|
|
98
|
+
'data-direction': 'back',
|
|
99
|
+
rel: 'prev',
|
|
100
|
+
href: input.page.previousHref,
|
|
101
|
+
},
|
|
102
|
+
input.labels.previous,
|
|
103
|
+
),
|
|
74
104
|
input.page.nextHref === null
|
|
75
105
|
? null
|
|
76
|
-
: h(
|
|
106
|
+
: h(
|
|
107
|
+
'a',
|
|
108
|
+
{ class: 'cr-arrow-link', rel: 'next', href: input.page.nextHref },
|
|
109
|
+
input.labels.next,
|
|
110
|
+
),
|
|
77
111
|
)
|
|
78
112
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The widget areas this theme names (contract D `theme@1.6`). Declaring them
|
|
3
|
+
* is what tells the host this theme draws the footer columns inside its own
|
|
4
|
+
* charcoal footer, on the footer's own twelve columns; the page areas are
|
|
5
|
+
* placed by the host in the shared `cg-sidebar-layout` markup, which
|
|
6
|
+
* `styles/widgets.css` sets as the margin of a printed menu card.
|
|
7
|
+
*/
|
|
8
|
+
export const widgetAreas: readonly {
|
|
9
|
+
readonly id: string
|
|
10
|
+
readonly label: string
|
|
11
|
+
readonly description?: string
|
|
12
|
+
}[] = [
|
|
13
|
+
{
|
|
14
|
+
id: 'sidebar',
|
|
15
|
+
label: 'Beside the page',
|
|
16
|
+
description: 'Beside a dish, a page that opens on its title, and search results.',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'content-after',
|
|
20
|
+
label: 'Under the page',
|
|
21
|
+
description: 'After a dish or a page, before the footer.',
|
|
22
|
+
},
|
|
23
|
+
]
|
package/src/styles/archive.css
CHANGED
|
@@ -1,84 +1,74 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* The taxonomy-term archive (contract D `theme@1.3`)
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* already styles — a breadcrumb, a sub-term row, a prev/next pager. The
|
|
6
|
-
* entry list reuses its own `cg-index__*` rules rather than a second set,
|
|
7
|
-
* so an archive looks like the rest of this theme's reading lists.
|
|
2
|
+
* The taxonomy-term archive (contract D `theme@1.3`): the page title and the
|
|
3
|
+
* index rows come from `base.css` and `menu.css`; this sheet adds the
|
|
4
|
+
* breadcrumb, the sub-terms and the pager.
|
|
8
5
|
*/
|
|
9
6
|
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
margin-inline: auto;
|
|
13
|
-
padding: var(--cg-s10) var(--cg-gutter);
|
|
7
|
+
.cr-archive__breadcrumb {
|
|
8
|
+
margin-block-end: var(--cr-s2);
|
|
14
9
|
}
|
|
15
10
|
|
|
16
|
-
.
|
|
17
|
-
margin: 0 0 var(--cg-s8);
|
|
18
|
-
font-size: var(--cg-text-2xl);
|
|
19
|
-
text-align: center;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.cg-archive__breadcrumb ol,
|
|
23
|
-
.cg-archive__children {
|
|
11
|
+
.cr-archive__trail {
|
|
24
12
|
display: flex;
|
|
25
13
|
flex-wrap: wrap;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
margin: 0 0 var(--cg-s4);
|
|
14
|
+
gap: 0 var(--cr-s2);
|
|
15
|
+
margin: 0;
|
|
29
16
|
padding: 0;
|
|
30
17
|
list-style: none;
|
|
31
|
-
|
|
18
|
+
color: var(--cr-ink-muted);
|
|
19
|
+
font-size: var(--cr-text-caption);
|
|
32
20
|
}
|
|
33
21
|
|
|
34
|
-
.
|
|
35
|
-
|
|
22
|
+
.cr-archive__trail li + li::before {
|
|
23
|
+
content: "/" / "";
|
|
24
|
+
margin-inline-end: var(--cr-s2);
|
|
25
|
+
color: var(--cr-ink-subtle);
|
|
36
26
|
}
|
|
37
27
|
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
padding: 0;
|
|
41
|
-
list-style: none;
|
|
28
|
+
.cr-archive__trail a {
|
|
29
|
+
color: var(--cr-ink-muted);
|
|
42
30
|
}
|
|
43
31
|
|
|
44
|
-
.
|
|
45
|
-
|
|
46
|
-
gap: var(--cg-s4);
|
|
47
|
-
padding-block: var(--cg-s5);
|
|
48
|
-
border-block-end: 1px solid var(--cg-line-soft);
|
|
32
|
+
.cr-archive__children {
|
|
33
|
+
padding-block: 0;
|
|
49
34
|
}
|
|
50
35
|
|
|
51
|
-
.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
36
|
+
.cr-archive__terms {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-wrap: wrap;
|
|
39
|
+
gap: var(--cr-s2) var(--cr-s8);
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding-block: var(--cr-s4);
|
|
42
|
+
padding-inline: 0;
|
|
43
|
+
border-block: var(--cr-rule) solid var(--cr-line);
|
|
44
|
+
list-style: none;
|
|
55
45
|
}
|
|
56
46
|
|
|
57
|
-
.
|
|
58
|
-
|
|
59
|
-
font-size: var(--
|
|
47
|
+
.cr-archive__term a {
|
|
48
|
+
font-family: var(--cr-font-display);
|
|
49
|
+
font-size: var(--cr-text-xl);
|
|
50
|
+
text-decoration-color: transparent;
|
|
60
51
|
}
|
|
61
52
|
|
|
62
|
-
.
|
|
63
|
-
color:
|
|
64
|
-
text-decoration: none;
|
|
53
|
+
.cr-archive__term a:hover {
|
|
54
|
+
text-decoration-color: currentColor;
|
|
65
55
|
}
|
|
66
56
|
|
|
67
|
-
.
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
.cr-archive__pager {
|
|
58
|
+
display: flex;
|
|
59
|
+
justify-content: space-between;
|
|
60
|
+
gap: var(--cr-s8);
|
|
61
|
+
margin-block-start: var(--cr-s10);
|
|
70
62
|
}
|
|
71
63
|
|
|
72
|
-
.
|
|
73
|
-
|
|
74
|
-
color: var(--cg-ink-muted);
|
|
64
|
+
.cr-archive__pager a[rel="next"] {
|
|
65
|
+
margin-inline-start: auto;
|
|
75
66
|
}
|
|
76
67
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
border-block-start: 1px solid var(--cg-line-soft);
|
|
68
|
+
@media (min-width: 64rem) {
|
|
69
|
+
.cr-archive .cr-index,
|
|
70
|
+
.cr-archive .cr-empty,
|
|
71
|
+
.cr-archive__pager {
|
|
72
|
+
grid-column: 1 / span 9;
|
|
73
|
+
}
|
|
84
74
|
}
|