@port60/template-kit 1.1.0 → 1.2.1
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/README.md +35 -1
- package/package.json +1 -1
- package/src/lib/agentsMd.mjs +48 -0
- package/src/vendor/contract/v2/islands.json +4 -3
- package/src/vendor/contract/v2/manifest.schema.json +49 -0
- package/src/vendor/contract/v2/sections.json +219 -1
- package/src/vendor/contract/v2/site.schema.json +4 -0
- package/src/vendor/contract/v2.lock.json +333 -4
- package/src/vendor/engine/presentation-capabilities.mjs +45 -0
- package/src/vendor/engine/section-heading-alignment.mjs +28 -0
- package/src/vendor/validator/collection-link-visibility.mjs +47 -0
- package/src/vendor/validator/heading-alignment.mjs +148 -0
- package/src/vendor/validator/navigation-modes.mjs +60 -0
- package/src/vendor/validator/platform-base.css +119 -0
- package/src/vendor/validator/presentation-proof.mjs +53 -0
- package/src/vendor/validator/preview-v2.mjs +10 -2
- package/src/vendor/validator/site-context-v2.mjs +17 -2
- package/src/vendor/validator/validate-v2.mjs +127 -3
- package/starter/manifest.json +1 -0
package/README.md
CHANGED
|
@@ -50,11 +50,45 @@ See the [AI quickstart](https://developers.port60.com/guides/ai-quickstart/).
|
|
|
50
50
|
|
|
51
51
|
## The contract
|
|
52
52
|
|
|
53
|
-
Kit 1.1
|
|
53
|
+
Kit 1.2.1 authors **port60-liquid@2**, content model **2.0**, using the contract under
|
|
54
54
|
`src/vendor/contract/v2`. Collection envelopes, independent header/footer navigation,
|
|
55
55
|
resolved actions and page-scoped sections are explicit. V1 sources need a deliberate migration,
|
|
56
56
|
not a manifest-only relabel. Historical v1 contracts remain frozen for existing platform pins.
|
|
57
57
|
|
|
58
|
+
### Photo-only hero playback in 1.2.1
|
|
59
|
+
|
|
60
|
+
The compatible host supplies `.hero-playback` on the `hero_carousel` island. Photo-only
|
|
61
|
+
templates may hide the optional dots and reveal playback on hover or keyboard focus,
|
|
62
|
+
while retaining a reachable control on touch devices. The preview supplies inactive
|
|
63
|
+
geometry only. Campaign/content carousel controls are unchanged. Deploy the compatible
|
|
64
|
+
host before publishing templates that depend on this control.
|
|
65
|
+
|
|
66
|
+
### Optional editor controls in 1.2.0
|
|
67
|
+
|
|
68
|
+
The editor only offers controls supported by the exact selected template version. Declare
|
|
69
|
+
and implement these capabilities together; the validator checks the rendered result:
|
|
70
|
+
|
|
71
|
+
- `supports.sectionHeadingAlignment`: supported section types and logical `start`, `center`
|
|
72
|
+
and `end` values. Put `data-p60-heading-align="{{ section.headingAlignment }}"` on the real
|
|
73
|
+
heading/eyebrow group. Move only that group within existing readable-width containers and
|
|
74
|
+
gutters at desktop widths of 1024px and above; preserve default and mobile layouts.
|
|
75
|
+
- `supports.navigationModes`: explicit Simple/Mega options and a default, with
|
|
76
|
+
`data-p60-navigation-mode="{{ site.nav.headerMode }}"` on the real header menu. Both modes
|
|
77
|
+
preserve the supplied menu tree and destinations. Do not infer support from highlights.
|
|
78
|
+
- `supports.sectionCollectionLinkVisibility`: sections whose existing onward collection link
|
|
79
|
+
has `data-p60-collection-link`. Keep that anchor in the DOM and add `hidden` only when
|
|
80
|
+
`section.showCollectionLink == false`, so the editor can reveal it without a page reload.
|
|
81
|
+
- `supports.heroImageLimit`: an integer from 1 to 6 alongside `supports.heroImagery: true`.
|
|
82
|
+
The limit must reflect actual rendering, not just a carousel declaration. Missing means
|
|
83
|
+
one photograph; no imagery support means none. Stored photographs are never truncated.
|
|
84
|
+
Hidden markup and unrelated CSS URL text cannot prove multi-photo capacity.
|
|
85
|
+
|
|
86
|
+
The compatible host must be deployed before these templates are published. Controls without
|
|
87
|
+
declared support remain unavailable, and older pinned versions keep their existing behaviour.
|
|
88
|
+
The visitor language switch remains dormant pending a separate multilingual-content flow;
|
|
89
|
+
organisation language, RTL/LTR support and interface translation remain available.
|
|
90
|
+
Generated AGENTS.md and CLAUDE.md contain the detailed authoring contract and validation loop.
|
|
91
|
+
|
|
58
92
|
### Added in 1.1.0
|
|
59
93
|
|
|
60
94
|
The v2 dialect adds `t` and `local_date`, matching the compatible platform host. Use
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@port60/template-kit",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Build Port60 site templates locally: scaffold, live-preview, validate against the platform contract, and package for studio upload. AI-agent ready: every scaffold ships AGENTS.md and validate emits machine-readable JSON.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/lib/agentsMd.mjs
CHANGED
|
@@ -72,6 +72,30 @@ Use nil checks, not Liquid default, wherever clearing has meaning. Keep generate
|
|
|
72
72
|
of raw section content. Mark an authored title only in the nonempty override branch. An inherited
|
|
73
73
|
heading has no data-p60-field marker.
|
|
74
74
|
|
|
75
|
+
Heading alignment is an optional per-section capability, not a global theme setting. Declare
|
|
76
|
+
supports.sectionHeadingAlignment as a map, for example {"services":["start","center","end"]}.
|
|
77
|
+
Each key must also be in supports.sections; list only the nonempty, unique subset you implement.
|
|
78
|
+
Place data-p60-heading-align="{{ section.headingAlignment }}" on the actual h1 to h6 heading,
|
|
79
|
+
its eyebrow, or a wrapper containing only that heading and eyebrow. The heading itself must be
|
|
80
|
+
inside/on a matching hook; do not mark the whole section, cards, media, body copy or actions.
|
|
81
|
+
Omit section.headingAlignment for the template's authored default. Never use a Liquid default
|
|
82
|
+
filter or a hardcoded active hook value: absent/unsupported values must leave the design alone.
|
|
83
|
+
Keep the empty hook on every visible heading at the default too, so the first editor choice
|
|
84
|
+
can update immediately. Only omit the heading and its hook together when that copy is hidden.
|
|
85
|
+
The platform applies start/center/end text alignment only at desktop widths (1024px and above).
|
|
86
|
+
Template CSS may position only the heading group within its existing template-owned content
|
|
87
|
+
container and gutters. Preserve its readable width; never widen it to the viewport, remove the
|
|
88
|
+
gutters or move the whole hero copy block. A full-bleed image can stay full bleed independently.
|
|
89
|
+
Introductions, body copy, buttons, cards, images and donation widgets keep their placement and
|
|
90
|
+
alignment. Scope local group-placement rules to that template's heading hook, explicit active
|
|
91
|
+
values and the same desktop breakpoint; do not introduce global margins or a new layout setting.
|
|
92
|
+
Default and mobile keep the template layout. Start/end follow text direction, including RTL.
|
|
93
|
+
Keep field markers and text unchanged; validate every advertised value and visually check every
|
|
94
|
+
Look. Prove visible heading alignment and bounded group placement with readable width retained,
|
|
95
|
+
unchanged surrounding content, reset and mobile; computed text-align alone is not visual proof.
|
|
96
|
+
This capability needs a coordinated host/kit release; keep existing published dependency pins
|
|
97
|
+
until that supporting kit version is available.
|
|
98
|
+
|
|
75
99
|
Declare supports.fieldMarkers:true when showing authored field markers. A marker such as
|
|
76
100
|
data-p60-field="title" or data-p60-field="items.{{ forloop.index0 }}.label" addresses only that
|
|
77
101
|
section's content. Its node must contain exactly the authored value. Use a span when punctuation
|
|
@@ -79,6 +103,13 @@ or generated text surrounds it. Never mark source records, generated labels or r
|
|
|
79
103
|
|
|
80
104
|
## Navigation and actions
|
|
81
105
|
|
|
106
|
+
Optional supports.navigationModes is {options:["simple","mega"],default:"mega"} (either supported
|
|
107
|
+
mode may be the default). It requires supports.layout and both working presentations. Mark the
|
|
108
|
+
header navigation root data-p60-navigation-mode="{{ site.nav.headerMode }}". The host resolves the
|
|
109
|
+
saved choice or declared default; missing capability keeps the historical layout. Do not infer
|
|
110
|
+
support from navigationHighlights. Both modes retain supplied destinations, node order and saved
|
|
111
|
+
metadata. Scope mode CSS to that marker and verify mobile, keyboard and no-JavaScript navigation.
|
|
112
|
+
|
|
82
113
|
site.nav.header and site.nav.footer are independent arrays. kind link has href; kind group has
|
|
83
114
|
null href and children. Use disclosure controls for groups, not fake links. Render two child
|
|
84
115
|
levels and preserve description, imageUrl and optional megaMenu.promo. No derived menus, CTA
|
|
@@ -89,6 +120,14 @@ site.actions.header and site.actions.hero are resolved actions or null. site.act
|
|
|
89
120
|
donate, volunteer or none. Do not infer actions from navigation. Authored hero override text
|
|
90
121
|
retains its field marker; resolved fallback actions do not.
|
|
91
122
|
|
|
123
|
+
Optional supports.sectionCollectionLinkVisibility lists supported collection section types with
|
|
124
|
+
an existing onward link. Mark only that anchor data-p60-collection-link, keep its supplied href
|
|
125
|
+
and existing label, and add hidden only when section.showCollectionLink == false. Missing/true
|
|
126
|
+
keeps the default link. Keep the hidden anchor for immediate editor updates; omit it only when
|
|
127
|
+
there is no supplied destination. Do not hide headings, cards or individual record links, invent
|
|
128
|
+
URLs, or add text/position controls. Unsupported saved preferences are retained but not rendered.
|
|
129
|
+
Both presentation capabilities need a coordinated host/kit release, not a speculative registry pin.
|
|
130
|
+
|
|
92
131
|
## Safety and design
|
|
93
132
|
|
|
94
133
|
- Output is escaped. Use raw only for contract-sanitised richtext.
|
|
@@ -101,8 +140,17 @@ retains its field marker; resolved fallback actions do not.
|
|
|
101
140
|
- Declare only what you render, and render what you declare. Capability matching is metadata,
|
|
102
141
|
not a transfer of route ownership or tenant entitlements.
|
|
103
142
|
- Hero photos need a palette scrim, a carousel for multiple photos and a designed no-photo state.
|
|
143
|
+
Declare supports.heroImagery:true plus supports.heroImageLimit as an integer from 1 to 6
|
|
144
|
+
matching the homeHero's actual capacity. Missing limit means one photograph; no hero imagery
|
|
145
|
+
means zero. A limit above one must render every distinct photograph in a fixture of that
|
|
146
|
+
size or place the hero_carousel island. A generic carousel declaration is not proof.
|
|
147
|
+
The editor reads the exact selected template version, never the catalogue's latest version.
|
|
148
|
+
Saved photographs are never truncated on template switches. Publish a new immutable version
|
|
149
|
+
with this declaration only after the matching host and kit release; preserve existing pins.
|
|
104
150
|
- Preserve settings and Looks. Use platform fonts and declared CSS tokens.
|
|
105
151
|
- The host owns lang/dir and Arabic fonts. Use logical CSS properties. Read site.locale.code.
|
|
152
|
+
- Do not add a visitor language selector. site.locale.languages is currently empty and the
|
|
153
|
+
legacy language_switch slot renders nothing. Interface catalogues are not translated tenant content.
|
|
106
154
|
- The next coordinated kit release adds t for supported interface phrases and local_date for
|
|
107
155
|
fixed Gregorian date/datetime formatting in UTC. Do not use these on registry kit 1.0.0.
|
|
108
156
|
Never translate authored text, infer prayer identities from translated names or convert
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"name": "hero_carousel",
|
|
107
107
|
"label": "Hero image carousel",
|
|
108
108
|
"status": "available",
|
|
109
|
-
"description": "
|
|
109
|
+
"description": "Photo-only rotation for homeHero.images (2+): advances every ~6s, pauses on hover and offers persistent Pause/Resume. Keyboard navigation or focus outside that button stops rotation until explicitly resumed. Reduced motion prevents autoplay, including after a live preference change. Supports horizontal touch swipe and direction-aware arrow keys, Home/End, plus optional dot navigation. Templates may hide dots when the .hero-playback control exists. They may reveal playback on photograph hover and keyboard focus, but must retain keyboard reachability, a visible focus indicator and a control that is available without hover on touch devices. This is separate from campaign/content carousels. The platform owns motion; the template styles the frame and the empty .hero-slide-scrim tonal layer using its palette. Fewer than 2 images render nothing: the template owns single/no-image states.",
|
|
110
110
|
"params": [],
|
|
111
111
|
"stylingApi": [
|
|
112
112
|
".hero-carousel",
|
|
@@ -117,7 +117,8 @@
|
|
|
117
117
|
".hero-slide-scrim",
|
|
118
118
|
".hero-dots",
|
|
119
119
|
".hero-dot",
|
|
120
|
-
".hero-dot--active"
|
|
120
|
+
".hero-dot--active",
|
|
121
|
+
".hero-playback"
|
|
121
122
|
]
|
|
122
123
|
},
|
|
123
124
|
{
|
|
@@ -140,7 +141,7 @@
|
|
|
140
141
|
"name": "language_switch",
|
|
141
142
|
"label": "Language switch",
|
|
142
143
|
"status": "available",
|
|
143
|
-
"description": "
|
|
144
|
+
"description": "Temporarily inactive: currently renders nothing. Localisation supports a site's language and text direction; translated tenant content and an explicit per-site language choice need a separate opt-in design. The host supplies locale and direction independently. Do not add a replacement visitor selector.",
|
|
144
145
|
"params": [],
|
|
145
146
|
"stylingApi": [
|
|
146
147
|
".language-switch",
|
|
@@ -91,6 +91,12 @@
|
|
|
91
91
|
"pages",
|
|
92
92
|
"sections"
|
|
93
93
|
],
|
|
94
|
+
"dependentSchemas": {
|
|
95
|
+
"heroImageLimit": {
|
|
96
|
+
"required": ["heroImagery"],
|
|
97
|
+
"properties": { "heroImagery": { "const": true } }
|
|
98
|
+
}
|
|
99
|
+
},
|
|
94
100
|
"properties": {
|
|
95
101
|
"pages": {
|
|
96
102
|
"type": "array",
|
|
@@ -151,6 +157,30 @@
|
|
|
151
157
|
"default": false,
|
|
152
158
|
"description": "True when the layout renders the `worship` context (the prayer/service-times rail). Declared honesty: the choosers badge worship-enabled tenants toward looks that show their times, and warn on looks that don't. Requires supports.layout; the layout must actually branch on `worship`."
|
|
153
159
|
},
|
|
160
|
+
"navigationModes": {
|
|
161
|
+
"type": "object",
|
|
162
|
+
"additionalProperties": false,
|
|
163
|
+
"required": ["options", "default"],
|
|
164
|
+
"properties": {
|
|
165
|
+
"options": {
|
|
166
|
+
"type": "array",
|
|
167
|
+
"minItems": 2,
|
|
168
|
+
"maxItems": 2,
|
|
169
|
+
"uniqueItems": true,
|
|
170
|
+
"items": { "enum": ["simple", "mega"] }
|
|
171
|
+
},
|
|
172
|
+
"default": { "enum": ["simple", "mega"] }
|
|
173
|
+
},
|
|
174
|
+
"description": "Explicit header presentation switch for this exact layout. Both simple and mega must be implemented without changing saved navigation nodes, destinations or metadata. Requires supports.layout. The host resolves an accepted saved menus.headerMode or this default into site.nav.headerMode. Mark the navigation root data-p60-navigation-mode with that resolved mode. Missing support preserves the historical layout and leaves saved preferences unused, never inferred from navigationHighlights."
|
|
175
|
+
},
|
|
176
|
+
"sectionCollectionLinkVisibility": {
|
|
177
|
+
"type": "array",
|
|
178
|
+
"minItems": 1,
|
|
179
|
+
"maxItems": 7,
|
|
180
|
+
"uniqueItems": true,
|
|
181
|
+
"items": { "enum": ["events", "articles", "courses", "campaigns", "services", "documents", "appealGrid"] },
|
|
182
|
+
"description": "Supported collection section types whose existing onward link may be hidden. Every entry must also be in supports.sections and render its supplied collection destination on a permanent data-p60-collection-link anchor. Only section.showCollectionLink == false adds hidden; absent or true retains the template default link. Keep its shared label and destination unchanged, and never hide the heading, records, cards or individual record links. No new URLs, text override or positioning control."
|
|
183
|
+
},
|
|
154
184
|
"navigationHighlights": {
|
|
155
185
|
"type": "boolean",
|
|
156
186
|
"default": false,
|
|
@@ -162,11 +192,30 @@
|
|
|
162
192
|
"description": "True when the sections mark which node shows which field with data-p60-field, so the editor can put the caret on the page instead of in a side panel. The address is inside that section's own content: data-p60-field=\"title\", or data-p60-field=\"items.{{ forloop.index0 }}.label\" for an entry in a list. Purely additive: the attribute is markup, the contract is untouched, and a template that marks nothing keeps the section-level editor. The validator reads the marks from the source and warns on any that does not name a field of that section. Missing or false leaves this exact template version editing in the panel.",
|
|
163
193
|
"$comment": "Follows the navigationHighlights pattern: declared honesty, proven by the validator."
|
|
164
194
|
},
|
|
195
|
+
"sectionHeadingAlignment": {
|
|
196
|
+
"type": "object",
|
|
197
|
+
"maxProperties": 16,
|
|
198
|
+
"propertyNames": { "enum": ["hero", "values", "cta", "homeHero", "impact", "events", "articles", "campaigns", "emergency", "stats", "appealGrid", "services", "documents", "people", "impactMap", "courses"] },
|
|
199
|
+
"additionalProperties": {
|
|
200
|
+
"type": "array",
|
|
201
|
+
"minItems": 1,
|
|
202
|
+
"maxItems": 3,
|
|
203
|
+
"uniqueItems": true,
|
|
204
|
+
"items": { "enum": ["start", "center", "end"] }
|
|
205
|
+
},
|
|
206
|
+
"description": "Explicit opt-in per supported section type to desktop heading alignment choices. Missing entries disable the editor control. The host projects section.headingAlignment only for declared options. Mark heading/eyebrow elements using data-p60-heading-align with that value. The shared base applies text-align at widths of at least 1024 CSS pixels; absent/empty hooks retain the template default at every width. The validator proves each declared option renders on real headings and cannot change unrelated content. No layout positioning is implied."
|
|
207
|
+
},
|
|
165
208
|
"heroImagery": {
|
|
166
209
|
"type": "boolean",
|
|
167
210
|
"default": false,
|
|
168
211
|
"description": "True when the homeHero renderer displays the tenant's hero photographs (homeHero.images, legacy imageUrl), always under a TREATMENT built from the template's own palette variables (scrim/tint/blend), never raw. Declared honesty, proven behaviourally at validation: the choosers badge photo-led tenants toward templates that show their images and warn on ones that won't. Requires the homeHero section among supports.sections."
|
|
169
212
|
},
|
|
213
|
+
"heroImageLimit": {
|
|
214
|
+
"type": "integer",
|
|
215
|
+
"minimum": 1,
|
|
216
|
+
"maximum": 6,
|
|
217
|
+
"description": "Maximum homeHero photographs this exact template version can present. Requires supports.heroImagery: true. Missing means one; no hero imagery means zero. Values above one require rendering every image in a fixture of the declared size or placing the hero_carousel island. Generic carousel behavior or island declarations alone do not opt in. This gates editor additions, never truncates saved photographs or changes an older artifact's rendering."
|
|
218
|
+
},
|
|
170
219
|
"behaviors": {
|
|
171
220
|
"type": "array",
|
|
172
221
|
"items": {
|
|
@@ -9,6 +9,17 @@
|
|
|
9
9
|
],
|
|
10
10
|
"description": "The page opener: a headline with an optional kicker and sanitised rich-text intro.",
|
|
11
11
|
"fields": [
|
|
12
|
+
{
|
|
13
|
+
"name": "headingAlignment",
|
|
14
|
+
"kind": "select",
|
|
15
|
+
"required": false,
|
|
16
|
+
"options": [
|
|
17
|
+
"start",
|
|
18
|
+
"center",
|
|
19
|
+
"end"
|
|
20
|
+
],
|
|
21
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
22
|
+
},
|
|
12
23
|
{
|
|
13
24
|
"name": "eyebrow",
|
|
14
25
|
"kind": "text",
|
|
@@ -45,6 +56,17 @@
|
|
|
45
56
|
],
|
|
46
57
|
"description": "A set of principles shown as cards or a numbered list, per the template.",
|
|
47
58
|
"fields": [
|
|
59
|
+
{
|
|
60
|
+
"name": "headingAlignment",
|
|
61
|
+
"kind": "select",
|
|
62
|
+
"required": false,
|
|
63
|
+
"options": [
|
|
64
|
+
"start",
|
|
65
|
+
"center",
|
|
66
|
+
"end"
|
|
67
|
+
],
|
|
68
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
69
|
+
},
|
|
48
70
|
{
|
|
49
71
|
"name": "eyebrow",
|
|
50
72
|
"kind": "text",
|
|
@@ -120,6 +142,17 @@
|
|
|
120
142
|
],
|
|
121
143
|
"description": "A closing band: heading, optional line, one button.",
|
|
122
144
|
"fields": [
|
|
145
|
+
{
|
|
146
|
+
"name": "headingAlignment",
|
|
147
|
+
"kind": "select",
|
|
148
|
+
"required": false,
|
|
149
|
+
"options": [
|
|
150
|
+
"start",
|
|
151
|
+
"center",
|
|
152
|
+
"end"
|
|
153
|
+
],
|
|
154
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
155
|
+
},
|
|
123
156
|
{
|
|
124
157
|
"name": "heading",
|
|
125
158
|
"kind": "text",
|
|
@@ -165,6 +198,17 @@
|
|
|
165
198
|
],
|
|
166
199
|
"description": "The home opener. EVERY field optional: eyebrow/title derive from branding when absent, the lead OMITS when absent (never a fabricated placeholder), buttons fall back to platform defaults.",
|
|
167
200
|
"fields": [
|
|
201
|
+
{
|
|
202
|
+
"name": "headingAlignment",
|
|
203
|
+
"kind": "select",
|
|
204
|
+
"required": false,
|
|
205
|
+
"options": [
|
|
206
|
+
"start",
|
|
207
|
+
"center",
|
|
208
|
+
"end"
|
|
209
|
+
],
|
|
210
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
211
|
+
},
|
|
168
212
|
{
|
|
169
213
|
"name": "eyebrow",
|
|
170
214
|
"kind": "text",
|
|
@@ -227,7 +271,7 @@
|
|
|
227
271
|
"name": "images",
|
|
228
272
|
"kind": "items",
|
|
229
273
|
"required": false,
|
|
230
|
-
"description": "Hero photographs (0-6, uploaded through the platform pipeline). One = a main image; several = rotation material
|
|
274
|
+
"description": "Hero photographs (0-6, uploaded through the platform pipeline). One = a main image; several = rotation material. A template with supports.heroImagery renders at least the first and may place the hero_carousel island (or a CSS scroll strip) for the rest. Declare supports.heroImageLimit above one to offer multiple photographs in the editor; missing means one, and absent heroImagery means zero. Saved photographs survive template switches and are never truncated by this capability. Like every field: absent means the template's designed no-photo state, never a placeholder.",
|
|
231
275
|
"itemFields": [
|
|
232
276
|
{
|
|
233
277
|
"name": "imageUrl",
|
|
@@ -295,6 +339,17 @@
|
|
|
295
339
|
],
|
|
296
340
|
"description": "What gifts make possible, optional intro plus icon/title/description cards. Claims must be truthful for the tenant.",
|
|
297
341
|
"fields": [
|
|
342
|
+
{
|
|
343
|
+
"name": "headingAlignment",
|
|
344
|
+
"kind": "select",
|
|
345
|
+
"required": false,
|
|
346
|
+
"options": [
|
|
347
|
+
"start",
|
|
348
|
+
"center",
|
|
349
|
+
"end"
|
|
350
|
+
],
|
|
351
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
352
|
+
},
|
|
298
353
|
{
|
|
299
354
|
"name": "eyebrow",
|
|
300
355
|
"kind": "text",
|
|
@@ -384,6 +439,23 @@
|
|
|
384
439
|
"kind": "widget",
|
|
385
440
|
"description": "Published events across registration modes. Render the supplied bounded site.content.events.items with this placement's authored introduction. Optional motion uses declared behaviours; ticket sales and RSVP stay on the platform-owned detail route supplied by each item.",
|
|
386
441
|
"fields": [
|
|
442
|
+
{
|
|
443
|
+
"name": "showCollectionLink",
|
|
444
|
+
"kind": "boolean",
|
|
445
|
+
"required": false,
|
|
446
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"name": "headingAlignment",
|
|
450
|
+
"kind": "select",
|
|
451
|
+
"required": false,
|
|
452
|
+
"options": [
|
|
453
|
+
"start",
|
|
454
|
+
"center",
|
|
455
|
+
"end"
|
|
456
|
+
],
|
|
457
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
458
|
+
},
|
|
387
459
|
{
|
|
388
460
|
"name": "eyebrow",
|
|
389
461
|
"kind": "text",
|
|
@@ -422,6 +494,23 @@
|
|
|
422
494
|
"kind": "widget",
|
|
423
495
|
"description": "Published articles from the supplied bounded site.content.articles.items. Render the records with this placement's authored introduction and link through the supplied item URLs. Article engagement and comments remain platform islands on the detail page.",
|
|
424
496
|
"fields": [
|
|
497
|
+
{
|
|
498
|
+
"name": "showCollectionLink",
|
|
499
|
+
"kind": "boolean",
|
|
500
|
+
"required": false,
|
|
501
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"name": "headingAlignment",
|
|
505
|
+
"kind": "select",
|
|
506
|
+
"required": false,
|
|
507
|
+
"options": [
|
|
508
|
+
"start",
|
|
509
|
+
"center",
|
|
510
|
+
"end"
|
|
511
|
+
],
|
|
512
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
513
|
+
},
|
|
425
514
|
{
|
|
426
515
|
"name": "eyebrow",
|
|
427
516
|
"kind": "text",
|
|
@@ -463,6 +552,23 @@
|
|
|
463
552
|
"campaignsLabel"
|
|
464
553
|
],
|
|
465
554
|
"fields": [
|
|
555
|
+
{
|
|
556
|
+
"name": "showCollectionLink",
|
|
557
|
+
"kind": "boolean",
|
|
558
|
+
"required": false,
|
|
559
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"name": "headingAlignment",
|
|
563
|
+
"kind": "select",
|
|
564
|
+
"required": false,
|
|
565
|
+
"options": [
|
|
566
|
+
"start",
|
|
567
|
+
"center",
|
|
568
|
+
"end"
|
|
569
|
+
],
|
|
570
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
571
|
+
},
|
|
466
572
|
{
|
|
467
573
|
"name": "eyebrow",
|
|
468
574
|
"kind": "text",
|
|
@@ -500,6 +606,17 @@
|
|
|
500
606
|
"causes"
|
|
501
607
|
],
|
|
502
608
|
"fields": [
|
|
609
|
+
{
|
|
610
|
+
"name": "headingAlignment",
|
|
611
|
+
"kind": "select",
|
|
612
|
+
"required": false,
|
|
613
|
+
"options": [
|
|
614
|
+
"start",
|
|
615
|
+
"center",
|
|
616
|
+
"end"
|
|
617
|
+
],
|
|
618
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
619
|
+
},
|
|
503
620
|
{
|
|
504
621
|
"name": "heading",
|
|
505
622
|
"kind": "text",
|
|
@@ -543,6 +660,17 @@
|
|
|
543
660
|
],
|
|
544
661
|
"description": "Big headline numbers, the at-a-glance impact band. Values are author-entered text (write them exactly as they should read), or, per item, a live figure the platform counts (`source`).",
|
|
545
662
|
"fields": [
|
|
663
|
+
{
|
|
664
|
+
"name": "headingAlignment",
|
|
665
|
+
"kind": "select",
|
|
666
|
+
"required": false,
|
|
667
|
+
"options": [
|
|
668
|
+
"start",
|
|
669
|
+
"center",
|
|
670
|
+
"end"
|
|
671
|
+
],
|
|
672
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
673
|
+
},
|
|
546
674
|
{
|
|
547
675
|
"name": "eyebrow",
|
|
548
676
|
"kind": "text",
|
|
@@ -626,6 +754,23 @@
|
|
|
626
754
|
"causes"
|
|
627
755
|
],
|
|
628
756
|
"fields": [
|
|
757
|
+
{
|
|
758
|
+
"name": "showCollectionLink",
|
|
759
|
+
"kind": "boolean",
|
|
760
|
+
"required": false,
|
|
761
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
"name": "headingAlignment",
|
|
765
|
+
"kind": "select",
|
|
766
|
+
"required": false,
|
|
767
|
+
"options": [
|
|
768
|
+
"start",
|
|
769
|
+
"center",
|
|
770
|
+
"end"
|
|
771
|
+
],
|
|
772
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
773
|
+
},
|
|
629
774
|
{
|
|
630
775
|
"name": "eyebrow",
|
|
631
776
|
"kind": "text",
|
|
@@ -715,6 +860,23 @@
|
|
|
715
860
|
"services"
|
|
716
861
|
],
|
|
717
862
|
"fields": [
|
|
863
|
+
{
|
|
864
|
+
"name": "showCollectionLink",
|
|
865
|
+
"kind": "boolean",
|
|
866
|
+
"required": false,
|
|
867
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
"name": "headingAlignment",
|
|
871
|
+
"kind": "select",
|
|
872
|
+
"required": false,
|
|
873
|
+
"options": [
|
|
874
|
+
"start",
|
|
875
|
+
"center",
|
|
876
|
+
"end"
|
|
877
|
+
],
|
|
878
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
879
|
+
},
|
|
718
880
|
{
|
|
719
881
|
"name": "eyebrow",
|
|
720
882
|
"kind": "text",
|
|
@@ -752,6 +914,23 @@
|
|
|
752
914
|
"resources"
|
|
753
915
|
],
|
|
754
916
|
"fields": [
|
|
917
|
+
{
|
|
918
|
+
"name": "showCollectionLink",
|
|
919
|
+
"kind": "boolean",
|
|
920
|
+
"required": false,
|
|
921
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
"name": "headingAlignment",
|
|
925
|
+
"kind": "select",
|
|
926
|
+
"required": false,
|
|
927
|
+
"options": [
|
|
928
|
+
"start",
|
|
929
|
+
"center",
|
|
930
|
+
"end"
|
|
931
|
+
],
|
|
932
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
933
|
+
},
|
|
755
934
|
{
|
|
756
935
|
"name": "eyebrow",
|
|
757
936
|
"kind": "text",
|
|
@@ -786,6 +965,17 @@
|
|
|
786
965
|
],
|
|
787
966
|
"description": "The key people behind the charity, trustees, staff, volunteers, as simple cards: name, position, an optional photograph (uploaded through the platform pipeline) and an optional one-line statement. Templates render a card grid that collapses to a single column on small screens; a card without a photo renders cleanly (initials or plain), never a placeholder face.",
|
|
788
967
|
"fields": [
|
|
968
|
+
{
|
|
969
|
+
"name": "headingAlignment",
|
|
970
|
+
"kind": "select",
|
|
971
|
+
"required": false,
|
|
972
|
+
"options": [
|
|
973
|
+
"start",
|
|
974
|
+
"center",
|
|
975
|
+
"end"
|
|
976
|
+
],
|
|
977
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
978
|
+
},
|
|
789
979
|
{
|
|
790
980
|
"name": "eyebrow",
|
|
791
981
|
"kind": "text",
|
|
@@ -878,6 +1068,17 @@
|
|
|
878
1068
|
"description": "The organisation's impact map: a themed map whose points link existing content (campaigns, causes, articles, events, places), each opening a card derived from the linked thing. Place the `map` island, it brings the map, the points and the cards; your template brings placement and tokens (the island theming contract).",
|
|
879
1069
|
"context": [],
|
|
880
1070
|
"fields": [
|
|
1071
|
+
{
|
|
1072
|
+
"name": "headingAlignment",
|
|
1073
|
+
"kind": "select",
|
|
1074
|
+
"required": false,
|
|
1075
|
+
"options": [
|
|
1076
|
+
"start",
|
|
1077
|
+
"center",
|
|
1078
|
+
"end"
|
|
1079
|
+
],
|
|
1080
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
1081
|
+
},
|
|
881
1082
|
{
|
|
882
1083
|
"name": "eyebrow",
|
|
883
1084
|
"kind": "text",
|
|
@@ -917,6 +1118,23 @@
|
|
|
917
1118
|
"home"
|
|
918
1119
|
],
|
|
919
1120
|
"fields": [
|
|
1121
|
+
{
|
|
1122
|
+
"name": "showCollectionLink",
|
|
1123
|
+
"kind": "boolean",
|
|
1124
|
+
"required": false,
|
|
1125
|
+
"description": "Only false hides this placement's existing onward collection link. Missing or true keeps the template default. Requires this exact template to declare supports.sectionCollectionLinkVisibility for this section. Keep a stable data-p60-collection-link anchor and add hidden only for false. The platform-supplied URL and shared label stay unchanged; headings, records and individual card links are unaffected."
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
"name": "headingAlignment",
|
|
1129
|
+
"kind": "select",
|
|
1130
|
+
"required": false,
|
|
1131
|
+
"options": [
|
|
1132
|
+
"start",
|
|
1133
|
+
"center",
|
|
1134
|
+
"end"
|
|
1135
|
+
],
|
|
1136
|
+
"description": "Desktop alignment of the heading and optional eyebrow. The template may position their heading-only group within its existing content container and gutters while preserving readable width. Only applied when this exact template declares supports.sectionHeadingAlignment for this section and option. Absent means template default. Start/end follow the site direction. Below 1024 CSS pixels the template retains its own layout. Introductions, body copy, buttons, cards, images and islands keep their placement and alignment; full-bleed imagery does not widen the heading bounds."
|
|
1137
|
+
},
|
|
920
1138
|
{
|
|
921
1139
|
"name": "eyebrow",
|
|
922
1140
|
"kind": "text",
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
"footer"
|
|
53
53
|
],
|
|
54
54
|
"properties": {
|
|
55
|
+
"headerMode": {
|
|
56
|
+
"enum": ["simple", "mega"],
|
|
57
|
+
"description": "Resolved header presentation only when the exact template declares navigationModes. The host uses the accepted saved preference or the declared default. Omitted for unsupported templates; never inferred from menu shape or highlights."
|
|
58
|
+
},
|
|
55
59
|
"header": {
|
|
56
60
|
"type": "array",
|
|
57
61
|
"items": {
|