@port60/template-kit 1.2.1 → 1.3.0
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 +38 -1
- package/package.json +1 -1
- package/src/commands/create.mjs +11 -0
- package/src/lib/agentsMd.mjs +176 -0
- package/src/vendor/contract/v2/dialect.json +2 -1
- package/src/vendor/contract/v2/manifest.schema.json +73 -2
- package/src/vendor/contract/v2/presentation.json +107 -0
- package/src/vendor/contract/v2/sections.json +120 -4
- package/src/vendor/contract/v2.lock.json +559 -7
- package/src/vendor/engine/budgets.mjs +0 -6
- package/src/vendor/engine/colour-roles.mjs +68 -0
- package/src/vendor/engine/content-footprint.mjs +0 -11
- package/src/vendor/engine/design-settings.mjs +34 -0
- package/src/vendor/engine/dialect.mjs +3 -10
- package/src/vendor/engine/locale.mjs +0 -5
- package/src/vendor/engine/majors.mjs +0 -5
- package/src/vendor/engine/presentation-capabilities.mjs +0 -2
- package/src/vendor/engine/section-fields.mjs +64 -0
- package/src/vendor/engine/section-heading-alignment.mjs +0 -2
- package/src/vendor/engine/section-presentation.mjs +127 -0
- package/src/vendor/validator/behaviors-runtime.js +1 -1
- package/src/vendor/validator/collection-link-visibility.mjs +0 -1
- package/src/vendor/validator/colour-treatment.mjs +154 -0
- package/src/vendor/validator/fixture-art.mjs +0 -15
- package/src/vendor/validator/focus.mjs +0 -5
- package/src/vendor/validator/fonts.mjs +0 -6
- package/src/vendor/validator/heading-alignment.mjs +0 -3
- package/src/vendor/validator/icons.mjs +0 -4
- package/src/vendor/validator/image-overlay.mjs +141 -0
- package/src/vendor/validator/intro-photo-framing.mjs +101 -0
- package/src/vendor/validator/model-reference-v2.mjs +0 -4
- package/src/vendor/validator/model-reference.mjs +0 -4
- package/src/vendor/validator/navigation-highlights.mjs +0 -3
- package/src/vendor/validator/presentation-proof.mjs +0 -2
- package/src/vendor/validator/preview-v1.mjs +3 -103
- package/src/vendor/validator/preview-v2.mjs +11 -105
- package/src/vendor/validator/section-fields.mjs +41 -0
- package/src/vendor/validator/section-layout.mjs +156 -0
- package/src/vendor/validator/section-presentation.mjs +225 -0
- package/src/vendor/validator/site-context-v2.mjs +17 -2
- package/src/vendor/validator/site-context.mjs +0 -14
- package/src/vendor/validator/validate-v1.mjs +4 -98
- package/src/vendor/validator/validate-v2.mjs +44 -103
- package/src/vendor/validator/validate.mjs +0 -2
- package/starter/assets/theme.css +55 -0
- package/starter/manifest.json +20 -0
- package/starter/sections/cta.liquid +2 -2
- package/starter/sections/hero.liquid +5 -3
- package/starter/sections/homeHero.liquid +6 -6
- package/starter/sections/values.liquid +2 -2
package/README.md
CHANGED
|
@@ -50,11 +50,48 @@ See the [AI quickstart](https://developers.port60.com/guides/ai-quickstart/).
|
|
|
50
50
|
|
|
51
51
|
## The contract
|
|
52
52
|
|
|
53
|
-
Kit 1.
|
|
53
|
+
Kit 1.3.0 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
|
+
### Editor design flexibility in 1.3.0
|
|
59
|
+
|
|
60
|
+
The editor offers only controls declared by the exact selected template version. The v2
|
|
61
|
+
presentation registry in `src/vendor/contract/v2/presentation.json` describes the bounded
|
|
62
|
+
choices and reset semantics, not evidence that every template implements each choice.
|
|
63
|
+
|
|
64
|
+
- `supports.sectionPresentation` can declare per-section heading size, vertical spacing,
|
|
65
|
+
coordinated colour treatments, photo-only Home hero overlays and About introduction layouts.
|
|
66
|
+
Keep permanent hooks on the actual heading or natural section root, with token CSS scoped
|
|
67
|
+
to the control's permitted properties. Preserve inherited defaults, Looks, content and islands.
|
|
68
|
+
An absent saved key inherits; reset removes the override. Unsupported stored choices stay
|
|
69
|
+
stored but do not enter the rendering projection.
|
|
70
|
+
- About introductions can independently declare `supports.sectionFields.hero` photograph and
|
|
71
|
+
alt-text fields, optionally with Fill/Show whole framing. Layout choices require those fields
|
|
72
|
+
and are logical `image-start`, `image-end` or `stacked` compositions. No photo means the
|
|
73
|
+
existing no-photo design, never a borrowed Home hero image or empty column. Reset restores
|
|
74
|
+
the author's framing, which need not match explicit Show whole.
|
|
75
|
+
- The v2 `colour_roles` filter adds bounded semantic paint roles to platform-sanitised rich
|
|
76
|
+
text. Use `{{ section.bodyHtml | colour_roles | raw }}` consistently; it is not a sanitiser
|
|
77
|
+
or permission to render untrusted HTML. Colour controls cannot change geometry or content.
|
|
78
|
+
- Existing theme settings may use `group: "header"` or `group: "footer"` when shared layout is
|
|
79
|
+
supported. These remain website-wide settings, with authored choices and defaults. Add section
|
|
80
|
+
uses existing exact section/layout declarations, not arbitrary presets or nested blocks.
|
|
81
|
+
- A v2 Impact map placement requires an explicit `section.mapSlug`. Missing, cleared or
|
|
82
|
+
unavailable selections show no replacement map. Custom preview content must pair that slug
|
|
83
|
+
with the same `impactMap.slug`; historical v1 behaviour is unchanged.
|
|
84
|
+
|
|
85
|
+
The scaffold demonstrates its own supported heading, spacing, colour and About-photo/layout
|
|
86
|
+
choices without advertising controls on unsuitable island surfaces. Structural validation is
|
|
87
|
+
not computed browser proof: verify every offered choice and reset across Looks, widths, sparse
|
|
88
|
+
content, keyboard and no-JavaScript states before declaring support.
|
|
89
|
+
|
|
90
|
+
Deploy the compatible platform first, publish this matching kit, then validate and publish new
|
|
91
|
+
immutable template versions using the registry package. Existing pins do not upgrade themselves.
|
|
92
|
+
See the [section authoring guide](https://developers.port60.com/guides/sections-and-data/) and
|
|
93
|
+
generated AGENTS.md/CLAUDE.md for the detailed markup, CSS and acceptance boundaries.
|
|
94
|
+
|
|
58
95
|
### Photo-only hero playback in 1.2.1
|
|
59
96
|
|
|
60
97
|
The compatible host supplies `.hero-playback` on the `hero_carousel` island. Photo-only
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@port60/template-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
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/commands/create.mjs
CHANGED
|
@@ -75,6 +75,17 @@ Start with \`npm install\`, then:
|
|
|
75
75
|
**Working with an AI agent?** Point it at this directory, \`AGENTS.md\` (and \`CLAUDE.md\`)
|
|
76
76
|
brief it on the contract, the rules and the validate loop.
|
|
77
77
|
|
|
78
|
+
Optional heading sizing and section spacing are independent per section: declare only tested
|
|
79
|
+
choices in \`supports.sectionPresentation\`. Keep \`data-p60-heading-scale\` on the actual
|
|
80
|
+
heading and \`data-p60-section-spacing\` on the natural outer section root, including when
|
|
81
|
+
the heading is hidden. Hooks stay permanently present and empty during inheritance. Define
|
|
82
|
+
responsive font sizes or block-axis root padding in CSS. Never change horizontal gutters,
|
|
83
|
+
card gaps, heights or island internals for spacing. An absent preference inherits;
|
|
84
|
+
reset removes the saved choice. Do not accept arbitrary CSS or numeric sizes. The kit proves
|
|
85
|
+
contract structure, while browser checks must prove visible effects and safe layouts.
|
|
86
|
+
See https://developers.port60.com/guides/sections-and-data/#bounded-heading-size and the
|
|
87
|
+
machine-readable https://developers.port60.com/schemas/template-presentation-v2.json registry.
|
|
88
|
+
|
|
78
89
|
Docs: https://developers.port60.com
|
|
79
90
|
`);
|
|
80
91
|
|
package/src/lib/agentsMd.mjs
CHANGED
|
@@ -96,11 +96,187 @@ unchanged surrounding content, reset and mobile; computed text-align alone is no
|
|
|
96
96
|
This capability needs a coordinated host/kit release; keep existing published dependency pins
|
|
97
97
|
until that supporting kit version is available.
|
|
98
98
|
|
|
99
|
+
## Bounded section presentation
|
|
100
|
+
|
|
101
|
+
The presentation.json registry defines platform-owned controls, value choices, reset addresses
|
|
102
|
+
and targets. It is published at https://developers.port60.com/schemas/template-presentation-v2.json
|
|
103
|
+
and documented at /reference/presentation/. Read the exact installed kit's registry for authoring;
|
|
104
|
+
the editor and a future agent must also check the exact selected template version's capabilities.
|
|
105
|
+
Do not infer support from a similar template, the catalogue's latest release or visible markup.
|
|
106
|
+
|
|
107
|
+
hero (About introduction) supports optional imageUrl and imageAlt only with the paired exact
|
|
108
|
+
section declaration supports.sectionFields:{"hero":["imageUrl","imageAlt"]}. This is independent
|
|
109
|
+
of layout choices: fixed compositions can support photographs without sectionLayout. Guard
|
|
110
|
+
missing images and preserve the original no-photo design. Use data-p60-field="imageUrl" only
|
|
111
|
+
on the actual img; escape imageAlt into alt, never an inline text marker. No placeholder,
|
|
112
|
+
invented photograph or borrowed Home hero photo is allowed. Unsafe or unsupported saved image
|
|
113
|
+
addresses stay stored but are omitted from rendering. The host accepts bounded root-relative
|
|
114
|
+
or HTTP(S) addresses, never credentials, whitespace, controls or backslashes.
|
|
115
|
+
|
|
116
|
+
Optional third field photoFraming in supports.sectionFields.hero offers fill/whole for the
|
|
117
|
+
Introduction photo, saved at section.content.photoFraming, never presentation.photoFraming.
|
|
118
|
+
Absent/reset inherits the author's composition, which may crop. Explicit whole shows the
|
|
119
|
+
uncropped natural image: width100%, heightauto, no blanket heightcap.
|
|
120
|
+
Keep data-p60-photo-framing="{{ section.photoFraming }}" on the actual marked img, empty when
|
|
121
|
+
inherited. Exact img token rules allow only object-fit:cover and aspect-ratio:1/1,4/3,3/2,16/9,2/1
|
|
122
|
+
for fill, or object-fit:contain and aspect-ratio:auto for whole. An optional root tag/classes
|
|
123
|
+
prefix and flat media/container conditions are allowed. Never change width, copy, grid, source,
|
|
124
|
+
alt or wrappers via framing. Prove actual crop vs natural whole in a browser with landscape,
|
|
125
|
+
portrait, square and panorama inputs; verify selector specificity does not mask the control.
|
|
126
|
+
The editor patches the existing image, then reconciles the section without refetching the photo
|
|
127
|
+
or navigating. Home hero framing and its default remain independent and unchanged.
|
|
128
|
+
|
|
129
|
+
sectionLayout is a per-section capability with image-start, image-end and stacked choices.
|
|
130
|
+
It is not a template-wide switch. Its hero target requires the independent photograph pair
|
|
131
|
+
above. The scaffold declares both; check the exact installed kit before authoring and do not
|
|
132
|
+
infer support from the registry alone. The layout proof preserves the natural root, unchanged
|
|
133
|
+
DOM order and separate frame/media/content roles.
|
|
134
|
+
Token CSS must be gated by data-p60-layout-has-media and may change only bounded grid tracks
|
|
135
|
+
and media/content grid-row/grid-column. No default token rule, arbitrary descendants, extra
|
|
136
|
+
containers, spacing, sizing, paint or platform islands. Start/end follow site direction.
|
|
137
|
+
Author opt-in needs exact default/reset equality, no-image safety and narrow single-column
|
|
138
|
+
browser evidence across every Look, plus long/cleared copy and repeated-section isolation.
|
|
139
|
+
|
|
140
|
+
headingScale and sectionSpacing are independent optional sectionPresentation controls. For example,
|
|
141
|
+
supports.sectionPresentation:{"homeHero":{"headingScale":{"options":["compact","standard","large"],"default":"standard"},"sectionSpacing":{"options":["compact","standard","spacious"],"default":"standard"}}}.
|
|
142
|
+
Every section key must appear in supports.sections. Declare only the two or three unique tokens
|
|
143
|
+
you have implemented, from compact/standard/large for headingScale, or compact/standard/spacious
|
|
144
|
+
for sectionSpacing; default must be one of those tokens. At least one control is required per
|
|
145
|
+
declared section; a spacing-only section does not need a heading. No raw CSS,
|
|
146
|
+
arbitrary numeric sizes, selectors or conditional expressions belong in this declaration.
|
|
147
|
+
The author defines a safe responsive size for each token in theme.css, not the editor or host.
|
|
148
|
+
|
|
149
|
+
imageOverlay is optional for homeHero only and requires supports.heroImagery:true. Declare
|
|
150
|
+
two or three choices from subtle/standard/strong and the inherited default. Save it at
|
|
151
|
+
section.content.presentation.imageOverlay; Liquid reads section.presentation.imageOverlay.
|
|
152
|
+
Keep data-p60-image-overlay on the existing first outer hero root, empty when inherited.
|
|
153
|
+
Mark photo-only wrappers data-p60-image-overlay-media and empty decorative overlay elements
|
|
154
|
+
data-p60-image-overlay-layer. Token CSS may change only palette-derived background,
|
|
155
|
+
background-image or background-color on marked layers, marked media ::before/::after, or
|
|
156
|
+
the documented .hero-slide-scrim beneath marked media. Never affect image opacity, filters,
|
|
157
|
+
geometry, copy, widgets or required text-readability scrims. Prove every static and carousel
|
|
158
|
+
branch, Fill and Whole, every Look, zero/one/two/max photos and no JavaScript. Default and reset
|
|
159
|
+
must match the original treatment; unsupported choices stay stored but do not render.
|
|
160
|
+
The inherited default can omit a CSS override; other choices need real matching layer rules.
|
|
161
|
+
Do not opt in a template whose branches cannot honour this. Starter deliberately remains
|
|
162
|
+
unsupported. Read /guides/sections-and-data/#bounded-photo-overlays for the full proof boundary.
|
|
163
|
+
|
|
164
|
+
colourTreatment is optional on non-island sections, excluding homeHero and impactMap. Declare
|
|
165
|
+
two or three unique standard/soft/contrast choices and an inherited default in sectionPresentation.
|
|
166
|
+
Persist only section.content.presentation.colourTreatment. Keep data-p60-colour-treatment on the
|
|
167
|
+
single natural outer root, empty when inherited. Mark authored descendants with
|
|
168
|
+
data-p60-colour-role="text|muted|accent|surface|border|link|button|secondary-button" (one role).
|
|
169
|
+
Nondefault token CSS must pair root background-color and color, cover every rendered role and
|
|
170
|
+
provide hover/focus-visible paint for link and button roles. Read existing Look palette variables;
|
|
171
|
+
never redefine global or section custom properties. Only color, background-color, border-color,
|
|
172
|
+
outline-color and text-decoration-color declarations are allowed; never use !important.
|
|
173
|
+
Do not alter geometry, images,
|
|
174
|
+
opacity, filters or islands. Never add padding/wrappers merely to make a colour control work.
|
|
175
|
+
Default-token CSS is forbidden so inheritance/default/reset keep the exact original design.
|
|
176
|
+
Use only flat natural root tag/classes + exact token, optionally followed by an owned role selector
|
|
177
|
+
and hover/focus-visible/active. No nested selectors or at-rules inside a token block.
|
|
178
|
+
Prove visible coordinated changes and contrast in every Look,
|
|
179
|
+
width, interaction and no-JavaScript state; structural CSS checks alone cannot prove that.
|
|
180
|
+
Read /guides/sections-and-data/#coordinated-section-colours for the full author contract.
|
|
181
|
+
|
|
182
|
+
For a colour-capable About introduction, render section.bodyHtml | colour_roles | raw on every
|
|
183
|
+
render, even inherited/default/reset. The v2 colour_roles filter decorates already-sanitised HTML:
|
|
184
|
+
h2/h3/h4=text, p/ul/ol/li=muted, a=link, blockquote=surface, hr=border. Cover every rendered role
|
|
185
|
+
and link hover/focus-visible. Inline emphasis inherits; images and islands are never decorated.
|
|
186
|
+
The filter only adds fixed attributes, preserving text, hrefs, markup and text-align. It is not
|
|
187
|
+
a sanitiser, never makes arbitrary HTML safe and does not bypass output escaping; raw stays explicit.
|
|
188
|
+
Do not conditionally replace or rewrap the body when changing a colour choice.
|
|
189
|
+
|
|
190
|
+
The saved address is section.content.presentation.headingScale. Inside Liquid the section variable
|
|
191
|
+
is already that content, so read section.presentation.headingScale. An absent key inherits your
|
|
192
|
+
existing CSS; reset removes it. Do not write a default into content or use a Liquid default filter.
|
|
193
|
+
An explicit choice equal to the default remains explicit. Unsupported saved choices stay stored
|
|
194
|
+
but are omitted from the render projection; switching templates must never erase them.
|
|
195
|
+
|
|
196
|
+
Keep data-p60-heading-scale="{{ section.presentation.headingScale }}" permanently on each actual
|
|
197
|
+
visible h1 to h6 section heading, including inherited headings without a field marker. The default
|
|
198
|
+
hook is empty, not absent. Hidden headings may omit both the heading and hook. Never put this
|
|
199
|
+
hook on a heading group, eyebrow, introduction, card title, action or platform island.
|
|
200
|
+
Write token-specific font-size rules scoped to this hook and the relevant heading family.
|
|
201
|
+
The declared default must have the same computed size as inheritance at each supported width
|
|
202
|
+
and Look. Do not change copy, heading levels or unrelated markup in response to the token.
|
|
203
|
+
|
|
204
|
+
For spacing, save section.content.presentation.sectionSpacing and read section.presentation.sectionSpacing
|
|
205
|
+
in Liquid. Keep data-p60-section-spacing="{{ section.presentation.sectionSpacing }}" permanently on
|
|
206
|
+
the natural outer section root, with an empty inherited hook, even when its heading is hidden.
|
|
207
|
+
Never add a wrapper or put the hook on an inner container, heading, card or platform island.
|
|
208
|
+
Token-specific CSS must target only that root and change only padding-block, padding-block-start,
|
|
209
|
+
padding-block-end, padding-top or padding-bottom. Never use padding shorthand or change horizontal
|
|
210
|
+
gutters, gaps, height, typography, descendants, pseudo-elements or island internals. Keep asymmetric
|
|
211
|
+
top/bottom authored padding intact in the default. The declared default must compute identically
|
|
212
|
+
to inheritance across widths and Looks. Omit spacing when the existing root has no suitable padding.
|
|
213
|
+
Multiple outer roots, including ancillary behaviour siblings, are unsupported; preserve them and
|
|
214
|
+
omit spacing rather than adding a wrapper. If clearing copy already omits the entire section,
|
|
215
|
+
all spacing choices must preserve that omission, never create a section in response to the token.
|
|
216
|
+
|
|
217
|
+
Kit preview, live preview and final rendering use the same accepted-value projection. The kit
|
|
218
|
+
checks declarations, heading/root hooks, structural isolation and token-specific CSS declarations;
|
|
219
|
+
it cannot prove computed CSS or visual quality. Check every option and reset in a browser across
|
|
220
|
+
Looks, narrow/wide viewports, long/empty/inherited headings, repeated sections and no JavaScript.
|
|
221
|
+
Prove visible size and spacing changes without overflow or changing unrelated layout. Respect reduced motion.
|
|
222
|
+
Existing headingAlignment and showCollectionLink addresses are unchanged. This is a bounded
|
|
223
|
+
presentation registry, not an arbitrary schema-driven editor or condition language.
|
|
224
|
+
Ship the compatible host and kit before publishing newly versioned template declarations.
|
|
225
|
+
|
|
226
|
+
The kit scaffold implements both controls on homeHero, hero, values and cta using its existing
|
|
227
|
+
heading families and natural root padding. people, campaigns and impactMap remain excluded:
|
|
228
|
+
their current utility or island roots have no suitable authored spacing surface. Preserve
|
|
229
|
+
the whole-photo hero's zero top padding and the form variant's distinct bottom padding.
|
|
230
|
+
|
|
99
231
|
Declare supports.fieldMarkers:true when showing authored field markers. A marker such as
|
|
100
232
|
data-p60-field="title" or data-p60-field="items.{{ forloop.index0 }}.label" addresses only that
|
|
101
233
|
section's content. Its node must contain exactly the authored value. Use a span when punctuation
|
|
102
234
|
or generated text surrounds it. Never mark source records, generated labels or resolved actions.
|
|
103
235
|
|
|
236
|
+
## Shared inspectors and section starting arrangements
|
|
237
|
+
|
|
238
|
+
An implemented v2 settings.schema entry may use group:"header" or group:"footer" with
|
|
239
|
+
supports.layout:true to appear in the matching shared website inspector. Historical v1 groups
|
|
240
|
+
and artifacts remain unchanged. This is explicit exact-artifact metadata, not a guessed
|
|
241
|
+
meaning of a key or template name. Existing color/select/toggle/font kinds, saved theme keys,
|
|
242
|
+
body data-p60s-<key> attributes and --p60s-<key> variables are unchanged. Implement every option
|
|
243
|
+
in the template's own CSS/markup; grouping alone does not create or prove a visual effect.
|
|
244
|
+
Author bounded artwork sizes per design, not universal ranges; leave unsupported placements
|
|
245
|
+
and choices absent.
|
|
246
|
+
Logo sizing affects artwork, not unrelated type. Keep useful no-logo and empty-social states,
|
|
247
|
+
menu destinations, identity, required legal links, consent and transactions. Verify every Look,
|
|
248
|
+
responsive width, keyboard and no-JavaScript state, plus exact inherited/default/reset equality.
|
|
249
|
+
|
|
250
|
+
Header/Footer controls share the existing theme working copy. Reset removes only the named
|
|
251
|
+
override; Design bulk reset preserves shared groups and unsupported saved choices. Explicit
|
|
252
|
+
defaults/false/blanks remain resettable. Looks still apply only their declared keys once.
|
|
253
|
+
Brand and menu controls retain their existing source records and website draft/publication flow.
|
|
254
|
+
Social addresses remain in Website settings with their own permissions and save lifecycle;
|
|
255
|
+
presentation choices never create or delete addresses or automatically save their source.
|
|
256
|
+
|
|
257
|
+
The visual Add section chooser uses exact supports.sections, allowed page types, compositions
|
|
258
|
+
and the existing per-section sectionLayout declarations. Its diagrams are schematic guides,
|
|
259
|
+
never screenshots or tenant content. There is no arbitrary presets schema or nested-container
|
|
260
|
+
model. Add inserts one new stable-key section with empty content or only the chosen layout
|
|
261
|
+
preference. Cancel has no effect; existing sections stay untouched. Template default omits the
|
|
262
|
+
override. Do not seed sample text, images, statistics, action links or source records. A layout
|
|
263
|
+
choice does not add a photograph, create an empty media column or change mobile ownership.
|
|
264
|
+
|
|
265
|
+
V2 impactMap requires explicit section.mapSlug. Missing/null/blank means no selected map;
|
|
266
|
+
never substitute the first public map. Unavailable, unpublished or archived selected maps have
|
|
267
|
+
no replacement fallback. Historical v1/built-in default-map behaviour is unchanged. The v2 kit
|
|
268
|
+
preview only shows its non-interactive map fixture when the selected slug matches that fixture:
|
|
269
|
+
canonical sample mapSlug:"our-work" matches impactMap.slug:"our-work"; minimal stays empty.
|
|
270
|
+
Custom demos must also explicitly select their matching fixture, never fetch tenant records.
|
|
271
|
+
|
|
272
|
+
Connected source choices are bounded typed references, not duplicate content or free expressions.
|
|
273
|
+
Map title/description/points stay in Maps; local introduction copy is only for templates that
|
|
274
|
+
actually render it. Cause buttons retain causeId and the public address copied when chosen,
|
|
275
|
+
not a live link expression following future slug changes. Missing sources keep saved choices
|
|
276
|
+
and show a notice; never choose replacements or create source records to fill a layout.
|
|
277
|
+
Use the compatible platform and kit before releasing newly versioned declarations. Source
|
|
278
|
+
tests, browser acceptance, local deployment and remote release are separate gates.
|
|
279
|
+
|
|
104
280
|
## Navigation and actions
|
|
105
281
|
|
|
106
282
|
Optional supports.navigationModes is {options:["simple","mega"],default:"mega"} (either supported
|
|
@@ -192,6 +192,75 @@
|
|
|
192
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.",
|
|
193
193
|
"$comment": "Follows the navigationHighlights pattern: declared honesty, proven by the validator."
|
|
194
194
|
},
|
|
195
|
+
"sectionFields": {
|
|
196
|
+
"type": "object",
|
|
197
|
+
"additionalProperties": false,
|
|
198
|
+
"properties": {
|
|
199
|
+
"hero": { "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true, "items": { "enum": ["imageUrl", "imageAlt", "photoFraming"] }, "allOf": [{ "contains": { "const": "imageUrl" } }, { "contains": { "const": "imageAlt" } }] }
|
|
200
|
+
},
|
|
201
|
+
"description": "Per-section opt-in to optional authored fields in this exact template version. The initial capability is the About introduction photograph: hero must also occur in supports.sections, and imageUrl/imageAlt are declared together. Optional photoFraming adds fill/whole on that photo; absent/reset inherits the author's composition while explicit whole shows the uncropped natural ratio. A fixed-layout photograph can be supported without sectionLayout. Missing support keeps saved photo fields but omits them from rendering and offers no new image picker. Validation proves supplied source/alt, no-photo omission, bounded framing and section ownership."
|
|
202
|
+
},
|
|
203
|
+
"sectionPresentation": {
|
|
204
|
+
"type": "object",
|
|
205
|
+
"maxProperties": 16,
|
|
206
|
+
"propertyNames": { "enum": ["hero", "values", "cta", "homeHero", "impact", "events", "articles", "campaigns", "emergency", "stats", "appealGrid", "services", "documents", "people", "impactMap", "courses"] },
|
|
207
|
+
"additionalProperties": {
|
|
208
|
+
"type": "object",
|
|
209
|
+
"additionalProperties": false,
|
|
210
|
+
"minProperties": 1,
|
|
211
|
+
"properties": {
|
|
212
|
+
"sectionLayout": {
|
|
213
|
+
"type": "object",
|
|
214
|
+
"additionalProperties": false,
|
|
215
|
+
"required": ["options", "default"],
|
|
216
|
+
"properties": {
|
|
217
|
+
"options": { "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true, "items": { "enum": ["image-start", "image-end", "stacked"] } },
|
|
218
|
+
"default": { "enum": ["image-start", "image-end", "stacked"] }
|
|
219
|
+
},
|
|
220
|
+
"description": "Per-section author opt-in for an About introduction with optional authored imagery. Start/end follow site direction. Permanent data-p60-section-layout on the single natural root, with data-p60-layout-has-media only when the photo exists and explicit frame/media/content roles. Token CSS changes only bounded grid tracks and slot placement, never copy, DOM order, imagery, gutters, typography or platform islands. Default/reset keeps inherited styling. Every narrow-screen choice retains authored single-column stacking."
|
|
221
|
+
},
|
|
222
|
+
"colourTreatment": {
|
|
223
|
+
"type": "object",
|
|
224
|
+
"additionalProperties": false,
|
|
225
|
+
"required": ["options", "default"],
|
|
226
|
+
"properties": {
|
|
227
|
+
"options": { "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true, "items": { "enum": ["standard", "soft", "contrast"] } },
|
|
228
|
+
"default": { "enum": ["standard", "soft", "contrast"] }
|
|
229
|
+
},
|
|
230
|
+
"description": "Coordinated section paint within the selected Look. Requires a permanent data-p60-colour-treatment on the single natural section root and bounded data-p60-colour-role descendants. Nondefault treatments coordinate root background/text and every marked role, including link/button hover and focus-visible. No shared palette rebinding, images, layout or platform islands. Home hero and impact maps are unsupported. Missing/reset preserves inherited styling."
|
|
231
|
+
},
|
|
232
|
+
"imageOverlay": {
|
|
233
|
+
"type": "object",
|
|
234
|
+
"additionalProperties": false,
|
|
235
|
+
"required": ["options", "default"],
|
|
236
|
+
"properties": {
|
|
237
|
+
"options": { "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true, "items": { "enum": ["subtle", "standard", "strong"] } },
|
|
238
|
+
"default": { "enum": ["subtle", "standard", "strong"] }
|
|
239
|
+
},
|
|
240
|
+
"description": "Home hero only. Safe palette-derived decorative photo treatment choices, independently proven for static and carousel imagery, Fill and Whole. Preserve required text-readability scrims. Missing/reset preserves inherited treatment; no source editing, image opacity or geometry changes."
|
|
241
|
+
},
|
|
242
|
+
"sectionSpacing": {
|
|
243
|
+
"type": "object",
|
|
244
|
+
"additionalProperties": false,
|
|
245
|
+
"required": ["options", "default"],
|
|
246
|
+
"properties": {
|
|
247
|
+
"options": { "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true, "items": { "enum": ["compact", "standard", "spacious"] } },
|
|
248
|
+
"default": { "enum": ["compact", "standard", "spacious"] }
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"headingScale": {
|
|
252
|
+
"type": "object",
|
|
253
|
+
"additionalProperties": false,
|
|
254
|
+
"required": ["options", "default"],
|
|
255
|
+
"properties": {
|
|
256
|
+
"options": { "type": "array", "minItems": 2, "maxItems": 3, "uniqueItems": true, "items": { "enum": ["compact", "standard", "large"] } },
|
|
257
|
+
"default": { "enum": ["compact", "standard", "large"] }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
"description": "Exact-version opt-in to independent platform-owned section presentation controls. Every key must be in supports.sections and declare at least one known control. Each control's default must occur in its options and describe inherited responsive styling. Saved explicit choices are projected into section.presentation; absence inherits without writing defaults. headingScale requires a permanent data-p60-heading-scale hook on the actual heading and authored font-size CSS. sectionSpacing requires a permanent data-p60-section-spacing hook on the natural outer section root and authored block-axis padding CSS, even without a heading; never alter horizontal gutters, card gaps, heights or island internals. Missing declarations are unsupported. No arbitrary values, conditions or CSS selectors are accepted."
|
|
263
|
+
},
|
|
195
264
|
"sectionHeadingAlignment": {
|
|
196
265
|
"type": "object",
|
|
197
266
|
"maxProperties": 16,
|
|
@@ -413,9 +482,11 @@
|
|
|
413
482
|
"type": "string",
|
|
414
483
|
"enum": [
|
|
415
484
|
"typography",
|
|
416
|
-
"looks"
|
|
485
|
+
"looks",
|
|
486
|
+
"header",
|
|
487
|
+
"footer"
|
|
417
488
|
],
|
|
418
|
-
"description": "Where the admin surfaces this knob:
|
|
489
|
+
"description": "Where the admin surfaces this knob: typography, looks, or the shared header/footer inspector. Header and footer groups explicitly declare template-authored global chrome settings, not a new content source. Every option must have template-owned CSS or markup; omitted groups never imply support. Other ungrouped knobs render under Template options."
|
|
419
490
|
},
|
|
420
491
|
"weights": {
|
|
421
492
|
"type": "array",
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"description": "Platform-owned presentation meanings. Templates declare supported choices; saved values remain tenant-owned. An absent override inherits the exact artifact's authored default. Hidden or unsupported values remain stored but are not projected into template rendering.",
|
|
4
|
+
"sectionTypes": ["hero", "values", "cta", "homeHero", "impact", "events", "articles", "campaigns", "emergency", "stats", "appealGrid", "services", "documents", "people", "impactMap", "courses"],
|
|
5
|
+
"legacySectionAliases": {"programmes": "services", "resources": "documents", "whatsOn": "events"},
|
|
6
|
+
"controls": {
|
|
7
|
+
"sectionLayout": {
|
|
8
|
+
"label": "Section layout",
|
|
9
|
+
"kind": "choice",
|
|
10
|
+
"scope": "section",
|
|
11
|
+
"sectionTypes": ["hero"],
|
|
12
|
+
"contentFields": {"imageUrl": "image", "imageAlt": "text"},
|
|
13
|
+
"address": ["presentation", "sectionLayout"],
|
|
14
|
+
"options": ["image-start", "image-end", "stacked"],
|
|
15
|
+
"labels": {"image-start": "Image at start", "image-end": "Image at end", "stacked": "Image above"},
|
|
16
|
+
"minimumOptions": 2,
|
|
17
|
+
"reset": "remove",
|
|
18
|
+
"target": "section-layout",
|
|
19
|
+
"responsive": "author-defined",
|
|
20
|
+
"attribute": "data-p60-section-layout",
|
|
21
|
+
"description": "Author-owned image/text layout for an explicitly supported About introduction. Start/end follow the site direction. Mark the single natural outer root and existing frame/media/content slots; token CSS changes only bounded grid tracks and slot placement when a photograph exists. Missing/reset preserves authored styling. Preserve copy, imagery, reading order, links, gutters and narrow-screen stacking; never invent absent media, add arbitrary containers or target platform islands. Every exact section declaration is independent; missing support is unsupported."
|
|
22
|
+
},
|
|
23
|
+
"colourTreatment": {
|
|
24
|
+
"label": "Colour treatment",
|
|
25
|
+
"kind": "choice",
|
|
26
|
+
"scope": "section",
|
|
27
|
+
"sectionTypes": ["hero", "values", "cta", "impact", "events", "articles", "campaigns", "emergency", "stats", "appealGrid", "services", "documents", "people", "courses"],
|
|
28
|
+
"address": ["presentation", "colourTreatment"],
|
|
29
|
+
"options": ["standard", "soft", "contrast"],
|
|
30
|
+
"labels": {"standard": "Standard", "soft": "Soft", "contrast": "Contrast"},
|
|
31
|
+
"minimumOptions": 2,
|
|
32
|
+
"reset": "remove",
|
|
33
|
+
"target": "section-colour-treatment",
|
|
34
|
+
"responsive": "author-defined",
|
|
35
|
+
"attribute": "data-p60-colour-treatment",
|
|
36
|
+
"description": "Coordinated author-owned section surface, copy, links and buttons within the selected Look. Missing/reset retains the original treatment. Mark the natural outer root and explicitly owned colour roles; token CSS changes paint only, never shared palette variables, imagery, layout or island internals. Home hero, impact maps and sections containing platform islands are not supported in this slice."
|
|
37
|
+
},
|
|
38
|
+
"headingScale": {
|
|
39
|
+
"label": "Heading size",
|
|
40
|
+
"kind": "choice",
|
|
41
|
+
"scope": "section",
|
|
42
|
+
"address": ["presentation", "headingScale"],
|
|
43
|
+
"options": ["compact", "standard", "large"],
|
|
44
|
+
"labels": {"compact": "Compact", "standard": "Standard", "large": "Large"},
|
|
45
|
+
"minimumOptions": 2,
|
|
46
|
+
"reset": "remove",
|
|
47
|
+
"target": "section-heading",
|
|
48
|
+
"responsive": "author-defined",
|
|
49
|
+
"attribute": "data-p60-heading-scale",
|
|
50
|
+
"description": "Changes only the actual section heading's responsive font size, never its heading level, eyebrow, body, cards, buttons or islands. Templates provide each size in their own CSS. The declared default describes inherited styling; it is not written into tenant content."
|
|
51
|
+
},
|
|
52
|
+
"sectionSpacing": {
|
|
53
|
+
"label": "Section spacing",
|
|
54
|
+
"kind": "choice",
|
|
55
|
+
"scope": "section",
|
|
56
|
+
"address": ["presentation", "sectionSpacing"],
|
|
57
|
+
"options": ["compact", "standard", "spacious"],
|
|
58
|
+
"labels": {"compact": "Compact", "standard": "Standard", "spacious": "Spacious"},
|
|
59
|
+
"minimumOptions": 2,
|
|
60
|
+
"reset": "remove",
|
|
61
|
+
"target": "section-root",
|
|
62
|
+
"responsive": "author-defined",
|
|
63
|
+
"attribute": "data-p60-section-spacing",
|
|
64
|
+
"description": "Changes only the natural outer section root's block-axis padding, never horizontal gutters, card gaps, heights or island internals. Templates provide each spacing in their own CSS. The declared default describes inherited styling; it is not written into tenant content. Keep the permanent hook even when the heading is hidden."
|
|
65
|
+
},
|
|
66
|
+
"imageOverlay": {
|
|
67
|
+
"label": "Photo overlay",
|
|
68
|
+
"kind": "choice",
|
|
69
|
+
"scope": "section",
|
|
70
|
+
"sectionTypes": ["homeHero"],
|
|
71
|
+
"requiresSupport": "heroImagery",
|
|
72
|
+
"address": ["presentation", "imageOverlay"],
|
|
73
|
+
"options": ["subtle", "standard", "strong"],
|
|
74
|
+
"labels": {"subtle": "Subtle", "standard": "Standard", "strong": "Strong"},
|
|
75
|
+
"minimumOptions": 2,
|
|
76
|
+
"reset": "remove",
|
|
77
|
+
"target": "section-image-treatment",
|
|
78
|
+
"responsive": "author-defined",
|
|
79
|
+
"attribute": "data-p60-image-overlay",
|
|
80
|
+
"description": "Changes only authored palette-derived decorative photo treatments in Home hero, never image opacity, source media, geometry, copy, widgets or a required readability scrim. Each exact artifact declares its safe choices and inherited default. Mark the existing photo wrapper with data-p60-image-overlay-media and empty decorative layers with data-p60-image-overlay-layer; token CSS may target those layers, marked wrapper pseudo-elements or the documented hero-slide-scrim. Missing and reset values preserve the authored treatment."
|
|
81
|
+
},
|
|
82
|
+
"headingAlignment": {
|
|
83
|
+
"label": "Desktop heading alignment",
|
|
84
|
+
"kind": "choice",
|
|
85
|
+
"scope": "section",
|
|
86
|
+
"address": ["headingAlignment"],
|
|
87
|
+
"options": ["start", "center", "end"],
|
|
88
|
+
"minimumOptions": 1,
|
|
89
|
+
"reset": "remove",
|
|
90
|
+
"target": "section-heading-and-eyebrow",
|
|
91
|
+
"responsive": "desktop-1024",
|
|
92
|
+
"attribute": "data-p60-heading-align",
|
|
93
|
+
"declaration": "sectionHeadingAlignment"
|
|
94
|
+
},
|
|
95
|
+
"showCollectionLink": {
|
|
96
|
+
"label": "Show collection link",
|
|
97
|
+
"kind": "toggle",
|
|
98
|
+
"scope": "section",
|
|
99
|
+
"address": ["showCollectionLink"],
|
|
100
|
+
"reset": "remove",
|
|
101
|
+
"target": "collection-link",
|
|
102
|
+
"responsive": "all",
|
|
103
|
+
"attribute": "data-p60-collection-link",
|
|
104
|
+
"declaration": "sectionCollectionLinkVisibility"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|