@port60/template-kit 0.5.0 → 0.7.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/package.json +1 -1
- package/src/vendor/contract/v1/context.json +722 -528
- package/src/vendor/contract/v1/sections.json +676 -577
- package/src/vendor/contract/v1.lock.json +446 -0
- package/src/vendor/validator/validate.mjs +49 -1
- package/starter/assets/theme.css +27 -0
- package/starter/manifest.json +48 -47
- package/starter/sections/people.liquid +26 -0
|
@@ -1,534 +1,728 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"description": "The site's primary navigation, platform-derived per tenant (pages that exist, features that are on). Render ALL of it — items a tenant doesn't have simply aren't in the list."
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"path": "nav.items[].label",
|
|
50
|
-
"availableIn": [
|
|
51
|
-
"layout"
|
|
52
|
-
],
|
|
53
|
-
"description": "The item's display label (tenant-chosen for some items — treat as text, it is escaped like everything else)."
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"path": "nav.items[].href",
|
|
57
|
-
"availableIn": [
|
|
58
|
-
"layout"
|
|
59
|
-
],
|
|
60
|
-
"description": "The item's destination path."
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"path": "nav.items[].cta",
|
|
64
|
-
"availableIn": [
|
|
65
|
-
"layout"
|
|
66
|
-
],
|
|
67
|
-
"description": "True for the call-to-action item (Donate) — style it prominently."
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"path": "nav.items[].children",
|
|
71
|
-
"availableIn": [
|
|
72
|
-
"layout"
|
|
73
|
-
],
|
|
74
|
-
"description": "Optional sub-items (e.g. a services dropdown). Absent on plain links; when present, render a dropdown/expandable group."
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
"path": "socials",
|
|
78
|
-
"availableIn": [
|
|
79
|
-
"layout"
|
|
80
|
-
],
|
|
81
|
-
"description": "The tenant's configured social links (possibly empty). Render icons via iconSvg — platform-generated markup, safe for the raw filter (the one exception beyond richtext fields)."
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"path": "socials[].platform",
|
|
85
|
-
"availableIn": [
|
|
86
|
-
"layout"
|
|
87
|
-
],
|
|
88
|
-
"description": "Platform key (facebook, instagram, x, …)."
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
"path": "socials[].url",
|
|
92
|
-
"availableIn": [
|
|
93
|
-
"layout"
|
|
94
|
-
],
|
|
95
|
-
"description": "The profile URL."
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"path": "socials[].iconSvg",
|
|
99
|
-
"availableIn": [
|
|
100
|
-
"layout"
|
|
101
|
-
],
|
|
102
|
-
"description": "The platform-drawn icon SVG for this network — output with | raw."
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
"path": "worship",
|
|
106
|
-
"availableIn": [
|
|
107
|
-
"layout"
|
|
108
|
-
],
|
|
109
|
-
"description": "The tenant's worship-schedule rail (prayer/service times), or null when not configured — ALWAYS branch on it. Faith-neutral: every label is tenant data. Render it as header chrome (the reference pattern is a utility bar above the nav); omit entirely when null. Rendering it requires declaring supports.worship in the manifest (the validator checks both directions) — the choosers use that declaration to steer worship-enabled tenants."
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"path": "worship.times",
|
|
113
|
-
"availableIn": [
|
|
114
|
-
"layout"
|
|
115
|
-
],
|
|
116
|
-
"description": "Up to 8 rows of {name, begins, congregation} — name is the prayer/service name; begins and congregation are display strings (times or short text), either may be null."
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
"path": "worship.beginsLabel",
|
|
120
|
-
"availableIn": [
|
|
121
|
-
"layout"
|
|
122
|
-
],
|
|
123
|
-
"description": "Row label for the begins times (tenant-set; defaults to 'Begins')."
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"path": "worship.congregationLabel",
|
|
127
|
-
"availableIn": [
|
|
128
|
-
"layout"
|
|
129
|
-
],
|
|
130
|
-
"description": "Row label for the congregation times (tenant-set; e.g. \"Jama'at\"; defaults to 'Congregation'). Only meaningful when at least one row carries a congregation value."
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"path": "worship.note",
|
|
134
|
-
"availableIn": [
|
|
135
|
-
"layout"
|
|
136
|
-
],
|
|
137
|
-
"description": "A short free-text line for the rail (e.g. \"Jum'a 13:15 & 14:15\"), or null."
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
"path": "worship.href",
|
|
141
|
-
"availableIn": [
|
|
142
|
-
"layout"
|
|
143
|
-
],
|
|
144
|
-
"description": "A same-site path the note links to (a service page with full timetables), or null."
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
"path": "worship.today",
|
|
148
|
-
"availableIn": [
|
|
149
|
-
"layout"
|
|
150
|
-
],
|
|
151
|
-
"description": "Today's date, platform-formatted (e.g. \"24 July 2026\")."
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"path": "worship.todayAlt",
|
|
155
|
-
"availableIn": [
|
|
156
|
-
"layout"
|
|
157
|
-
],
|
|
158
|
-
"description": "Today in the tenant's alternate calendar (Islamic civil calendar, e.g. \"11 Safar 1448\") when they opted in, else null — always branch."
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"path": "events",
|
|
162
|
-
"availableIn": [
|
|
163
|
-
"page:events"
|
|
164
|
-
],
|
|
165
|
-
"description": "The tenant's published events, soonest first — a CURATED read-only view for display. Transactional steps (RSVP, ticket purchase) stay platform-owned on the detail view."
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
"path": "events[].id",
|
|
169
|
-
"availableIn": [
|
|
170
|
-
"page:events"
|
|
171
|
-
],
|
|
172
|
-
"description": "Stable event id."
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
"path": "events[].name",
|
|
176
|
-
"availableIn": [
|
|
177
|
-
"page:events"
|
|
178
|
-
],
|
|
179
|
-
"description": "The event's name."
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
"path": "events[].description",
|
|
183
|
-
"availableIn": [
|
|
184
|
-
"page:events"
|
|
185
|
-
],
|
|
186
|
-
"description": "Plain-text description, or null — branch on it."
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
"path": "events[].registrationMode",
|
|
190
|
-
"availableIn": [
|
|
191
|
-
"page:events"
|
|
192
|
-
],
|
|
193
|
-
"description": "INFO (no sign-up), RSVP (free sign-up) or TICKETED (paid)."
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
"path": "events[].startsAt",
|
|
197
|
-
"availableIn": [
|
|
198
|
-
"page:events"
|
|
199
|
-
],
|
|
200
|
-
"description": "ISO-8601 start — format with the date filter."
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
"path": "events[].endsAt",
|
|
204
|
-
"availableIn": [
|
|
205
|
-
"page:events"
|
|
206
|
-
],
|
|
207
|
-
"description": "ISO-8601 end, or null."
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
"path": "events[].venueName",
|
|
211
|
-
"availableIn": [
|
|
212
|
-
"page:events"
|
|
213
|
-
],
|
|
214
|
-
"description": "Venue name, or null (online events may have none)."
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
"path": "events[].online",
|
|
218
|
-
"availableIn": [
|
|
219
|
-
"page:events"
|
|
220
|
-
],
|
|
221
|
-
"description": "True for online events."
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
"path": "events[].imageUrl",
|
|
225
|
-
"availableIn": [
|
|
226
|
-
"page:events"
|
|
227
|
-
],
|
|
228
|
-
"description": "Promo image URL, or null — always branch."
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
"path": "events[].onSale",
|
|
232
|
-
"availableIn": [
|
|
233
|
-
"page:events"
|
|
234
|
-
],
|
|
235
|
-
"description": "False before sales open."
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
"path": "events[].soldOut",
|
|
239
|
-
"availableIn": [
|
|
240
|
-
"page:events"
|
|
241
|
-
],
|
|
242
|
-
"description": "True when no capacity remains."
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
"path": "events[].priceFrom",
|
|
246
|
-
"availableIn": [
|
|
247
|
-
"page:events"
|
|
248
|
-
],
|
|
249
|
-
"description": "The cheapest ticket price (number), or null for free/INFO events."
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
"path": "events[].currency",
|
|
253
|
-
"availableIn": [
|
|
254
|
-
"page:events"
|
|
255
|
-
],
|
|
256
|
-
"description": "ISO currency code for priceFrom, or null."
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
"path": "events[].detailHref",
|
|
260
|
-
"availableIn": [
|
|
261
|
-
"page:events"
|
|
262
|
-
],
|
|
263
|
-
"description": "The canonical link to this event's detail view — always use this, never build URLs yourself."
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
"path": "course",
|
|
267
|
-
"availableIn": [
|
|
268
|
-
"page:course"
|
|
269
|
-
],
|
|
270
|
-
"description": "The course this page addresses — a CURATED read-only view for display. The enrolment journey itself is the platform-owned course_enrol island; place it, never rebuild it."
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
"path": "course.id",
|
|
274
|
-
"availableIn": [
|
|
275
|
-
"page:course"
|
|
276
|
-
],
|
|
277
|
-
"description": "Stable course id."
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
"path": "course.title",
|
|
281
|
-
"availableIn": [
|
|
282
|
-
"page:course"
|
|
283
|
-
],
|
|
284
|
-
"description": "The course's title."
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
"path": "course.description",
|
|
288
|
-
"availableIn": [
|
|
289
|
-
"page:course"
|
|
290
|
-
],
|
|
291
|
-
"description": "Plain-text summary, or null — branch on it. Prefer aboutHtml for the body when present."
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
"path": "course.aboutHtml",
|
|
295
|
-
"availableIn": [
|
|
296
|
-
"page:course"
|
|
297
|
-
],
|
|
298
|
-
"description": "The tenant-authored About page as SANITISED HTML (platform-sanitised on save; images resolved) — render with the raw filter inside your prose styles, or null when not written."
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
"path": "course.imageUrl",
|
|
302
|
-
"availableIn": [
|
|
303
|
-
"page:course"
|
|
304
|
-
],
|
|
305
|
-
"description": "The MAIN image (hero) URL, or null — always branch."
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
"path": "course.venue",
|
|
309
|
-
"availableIn": [
|
|
310
|
-
"page:course"
|
|
311
|
-
],
|
|
312
|
-
"description": "Venue display text, or null."
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
"path": "course.audience",
|
|
316
|
-
"availableIn": [
|
|
317
|
-
"page:course"
|
|
318
|
-
],
|
|
319
|
-
"description": "EVERYONE, or CHILD for children-only courses (parents enrol their children)."
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
"path": "course.billingMode",
|
|
323
|
-
"availableIn": [
|
|
324
|
-
"page:course"
|
|
325
|
-
],
|
|
326
|
-
"description": "UPFRONT (one payment), TERM (committed term fee), or ROLLING (monthly with notice)."
|
|
327
|
-
},
|
|
328
|
-
{
|
|
329
|
-
"path": "course.termStart",
|
|
330
|
-
"availableIn": [
|
|
331
|
-
"page:course"
|
|
332
|
-
],
|
|
333
|
-
"description": "ISO date the term starts, or null — format with the date filter."
|
|
334
|
-
},
|
|
335
|
-
{
|
|
336
|
-
"path": "course.termEnd",
|
|
337
|
-
"availableIn": [
|
|
338
|
-
"page:course"
|
|
339
|
-
],
|
|
340
|
-
"description": "ISO date the term ends, or null."
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
"path": "course.currency",
|
|
344
|
-
"availableIn": [
|
|
345
|
-
"page:course"
|
|
346
|
-
],
|
|
347
|
-
"description": "ISO currency code for priceFrom."
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
"path": "course.priceFrom",
|
|
351
|
-
"availableIn": [
|
|
352
|
-
"page:course"
|
|
353
|
-
],
|
|
354
|
-
"description": "The cheapest priced option (number), or null when every option is free."
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
"path": "course.soldOut",
|
|
358
|
-
"availableIn": [
|
|
359
|
-
"page:course"
|
|
360
|
-
],
|
|
361
|
-
"description": "True when no option has places left (the island shows the standard note)."
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
"path": "course.backHref",
|
|
365
|
-
"availableIn": [
|
|
366
|
-
"page:course"
|
|
367
|
-
],
|
|
368
|
-
"description": "The canonical link back to the courses listing — always use this."
|
|
369
|
-
}
|
|
370
|
-
],
|
|
371
|
-
"fixtures": {
|
|
372
|
-
"brand": {
|
|
373
|
-
"name": "Fixture Charity",
|
|
374
|
-
"tagline": "A fixture tagline.",
|
|
375
|
-
"logoUrl": null,
|
|
376
|
-
"logoType": "full"
|
|
377
|
-
},
|
|
378
|
-
"layout": {
|
|
379
|
-
"nav": {
|
|
380
|
-
"items": [
|
|
381
|
-
{
|
|
382
|
-
"label": "Home",
|
|
383
|
-
"href": "/",
|
|
384
|
-
"cta": false
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
"label": "About us",
|
|
388
|
-
"href": "/about",
|
|
389
|
-
"cta": false
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
"label": "Events",
|
|
393
|
-
"href": "/events",
|
|
394
|
-
"cta": false
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
"label": "Services",
|
|
398
|
-
"href": "/services",
|
|
399
|
-
"cta": false,
|
|
400
|
-
"children": [
|
|
401
|
-
{
|
|
402
|
-
"label": "Food bank",
|
|
403
|
-
"href": "/services?service=food-bank"
|
|
404
|
-
},
|
|
405
|
-
{
|
|
406
|
-
"label": "Youth club",
|
|
407
|
-
"href": "/services?service=youth-club"
|
|
408
|
-
}
|
|
2
|
+
"description": "The data context templates render with. Templates receive ONLY platform-provided data — never secrets, never other tenants' data. Additive-only within a contract major. Section renderers get {section, brand}; the layout gets {brand, nav, socials}; page templates (pages/{page}.liquid) get their page's documented objects + brand.",
|
|
3
|
+
"variables": [
|
|
4
|
+
{
|
|
5
|
+
"path": "section",
|
|
6
|
+
"availableIn": [
|
|
7
|
+
"section"
|
|
8
|
+
],
|
|
9
|
+
"description": "The typed content of the section being rendered — its shape is the section type's fields (see the section catalogue)."
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"path": "brand.name",
|
|
13
|
+
"availableIn": [
|
|
14
|
+
"section",
|
|
15
|
+
"layout"
|
|
16
|
+
],
|
|
17
|
+
"description": "The charity's display name."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "brand.tagline",
|
|
21
|
+
"availableIn": [
|
|
22
|
+
"section",
|
|
23
|
+
"layout"
|
|
24
|
+
],
|
|
25
|
+
"description": "The charity's tagline."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": "brand.logoUrl",
|
|
29
|
+
"availableIn": [
|
|
30
|
+
"layout"
|
|
31
|
+
],
|
|
32
|
+
"description": "The charity's logo URL, or null when none is set — always branch on it."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"path": "brand.logoType",
|
|
36
|
+
"availableIn": [
|
|
37
|
+
"layout"
|
|
38
|
+
],
|
|
39
|
+
"description": "'full' (the image already contains the name — show it alone) or 'icon' (a mark — show it beside brand.name)."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "brand.footerLogoUrl",
|
|
43
|
+
"description": "Optional FOOTER mark (often a lighter or single-colour logo variant the tenant uploads for dark footers), or null — always branch. When unset, fall back to your own choice: the main logo, or the name as text.",
|
|
44
|
+
"availableIn": [
|
|
45
|
+
"layout"
|
|
409
46
|
]
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
"
|
|
413
|
-
"
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"path": "nav.items",
|
|
50
|
+
"availableIn": [
|
|
51
|
+
"layout"
|
|
52
|
+
],
|
|
53
|
+
"description": "The site's primary navigation. By default platform-derived per tenant (pages that exist, features that are on); when the tenant has curated a header menu, this IS that menu instead — the same { label, href, cta?, external?, children? } shape either way, so render ALL of it exactly as before."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": "nav.items[].label",
|
|
57
|
+
"availableIn": [
|
|
58
|
+
"layout"
|
|
59
|
+
],
|
|
60
|
+
"description": "The item's display label (tenant-chosen for some items — treat as text, it is escaped like everything else)."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"path": "nav.items[].href",
|
|
64
|
+
"availableIn": [
|
|
65
|
+
"layout"
|
|
66
|
+
],
|
|
67
|
+
"description": "The item's destination path."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"path": "nav.items[].cta",
|
|
71
|
+
"availableIn": [
|
|
72
|
+
"layout"
|
|
73
|
+
],
|
|
74
|
+
"description": "True for the call-to-action item (Donate) — style it prominently."
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"path": "nav.items[].children",
|
|
78
|
+
"availableIn": [
|
|
79
|
+
"layout"
|
|
80
|
+
],
|
|
81
|
+
"description": "Optional sub-items (e.g. a services dropdown, or a tenant-curated 'About us' group). Absent on plain links; when present, render a dropdown/expandable group. Children are { label, href, external? } — one level only."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"path": "nav.items[].external",
|
|
85
|
+
"availableIn": [
|
|
86
|
+
"layout"
|
|
87
|
+
],
|
|
88
|
+
"description": "True when the item points off-site (a tenant-curated external link) — add target=\"_blank\" rel=\"noopener\". Absent/false for internal links."
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"path": "nav.footer",
|
|
92
|
+
"availableIn": [
|
|
93
|
+
"layout"
|
|
94
|
+
],
|
|
95
|
+
"description": "The tenant's curated FOOTER menu — the same item shape as nav.items[] (label, href, cta?, external?, children?). EMPTY when the tenant hasn't built one, so branch on nav.footer.size before rendering a footer-menu block (derive or omit). Optional to support — a template that ignores it simply shows its own footer."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"path": "nav.derived",
|
|
99
|
+
"availableIn": [
|
|
100
|
+
"layout"
|
|
101
|
+
],
|
|
102
|
+
"description": "The platform's AUTOMATIC nav (same item shape as nav.items[]), always present even when the tenant has curated nav.items. Use it when you want the auto, feature-aware list somewhere regardless of the tenant's header curation; most templates just render nav.items."
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"path": "socials",
|
|
106
|
+
"availableIn": [
|
|
107
|
+
"layout"
|
|
108
|
+
],
|
|
109
|
+
"description": "The tenant's configured social links (possibly empty). Render icons via iconSvg — platform-generated markup, safe for the raw filter (the one exception beyond richtext fields)."
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"path": "socials[].platform",
|
|
113
|
+
"availableIn": [
|
|
114
|
+
"layout"
|
|
115
|
+
],
|
|
116
|
+
"description": "Platform key (facebook, instagram, x, …)."
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"path": "socials[].url",
|
|
120
|
+
"availableIn": [
|
|
121
|
+
"layout"
|
|
122
|
+
],
|
|
123
|
+
"description": "The profile URL."
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"path": "socials[].iconSvg",
|
|
127
|
+
"availableIn": [
|
|
128
|
+
"layout"
|
|
129
|
+
],
|
|
130
|
+
"description": "The platform-drawn icon SVG for this network — output with | raw."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"path": "worship",
|
|
134
|
+
"availableIn": [
|
|
135
|
+
"layout"
|
|
136
|
+
],
|
|
137
|
+
"description": "The tenant's worship-schedule rail (prayer/service times), or null when not configured — ALWAYS branch on it. Faith-neutral: every label is tenant data. Render it as header chrome (the reference pattern is a utility bar above the nav); omit entirely when null. Rendering it requires declaring supports.worship in the manifest (the validator checks both directions) — the choosers use that declaration to steer worship-enabled tenants."
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"path": "worship.times",
|
|
141
|
+
"availableIn": [
|
|
142
|
+
"layout"
|
|
143
|
+
],
|
|
144
|
+
"description": "Up to 8 rows of {name, begins, congregation} — name is the prayer/service name; begins and congregation are display strings (times or short text), either may be null."
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"path": "worship.beginsLabel",
|
|
148
|
+
"availableIn": [
|
|
149
|
+
"layout"
|
|
150
|
+
],
|
|
151
|
+
"description": "Row label for the begins times (tenant-set; defaults to 'Begins')."
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"path": "worship.congregationLabel",
|
|
155
|
+
"availableIn": [
|
|
156
|
+
"layout"
|
|
157
|
+
],
|
|
158
|
+
"description": "Row label for the congregation times (tenant-set; e.g. \"Jama'at\"; defaults to 'Congregation'). Only meaningful when at least one row carries a congregation value."
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"path": "worship.note",
|
|
162
|
+
"availableIn": [
|
|
163
|
+
"layout"
|
|
164
|
+
],
|
|
165
|
+
"description": "A short free-text line for the rail (e.g. \"Jum'a 13:15 & 14:15\"), or null."
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"path": "worship.href",
|
|
169
|
+
"availableIn": [
|
|
170
|
+
"layout"
|
|
171
|
+
],
|
|
172
|
+
"description": "A same-site path the note links to (a service page with full timetables), or null."
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"path": "worship.today",
|
|
176
|
+
"availableIn": [
|
|
177
|
+
"layout"
|
|
178
|
+
],
|
|
179
|
+
"description": "Today's date, platform-formatted (e.g. \"24 July 2026\")."
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"path": "worship.todayAlt",
|
|
183
|
+
"availableIn": [
|
|
184
|
+
"layout"
|
|
185
|
+
],
|
|
186
|
+
"description": "Today in the tenant's alternate calendar (Islamic civil calendar, e.g. \"11 Safar 1448\") when they opted in, else null — always branch."
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"path": "events",
|
|
190
|
+
"availableIn": [
|
|
191
|
+
"page:events",
|
|
192
|
+
"section:events"
|
|
193
|
+
],
|
|
194
|
+
"description": "The tenant's published events, soonest first — a CURATED read-only view for display. On page:events it is every published event; on section:events it is the TICKETED ones (the section's purpose). Transactional steps (RSVP, ticket purchase) stay platform-owned on the detail view — link with detailHref, never rebuild those flows."
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"path": "infoEvents",
|
|
198
|
+
"availableIn": [
|
|
199
|
+
"section:whatsOn"
|
|
200
|
+
],
|
|
201
|
+
"description": "The tenant's INFO events (special days — no sign-up, no payment), soonest first. The same curated event shape as events[]. Render them your way, or place {% island 'whats_on_strip' %} for the ready-made strip. Empty when none — render nothing you invent (derive or omit)."
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"path": "latestArticles",
|
|
205
|
+
"availableIn": [
|
|
206
|
+
"section:articles"
|
|
207
|
+
],
|
|
208
|
+
"description": "The newest published articles (up to 6), newest first. Render them your way, or place {% island 'latest_articles' %} for the ready-made strip. Empty when none — derive or omit."
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"path": "latestArticles[].title",
|
|
212
|
+
"availableIn": [
|
|
213
|
+
"section:articles"
|
|
214
|
+
],
|
|
215
|
+
"description": "The article's title."
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"path": "latestArticles[].href",
|
|
219
|
+
"availableIn": [
|
|
220
|
+
"section:articles"
|
|
221
|
+
],
|
|
222
|
+
"description": "The canonical link to the article — always use this."
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"path": "latestArticles[].excerpt",
|
|
226
|
+
"availableIn": [
|
|
227
|
+
"section:articles"
|
|
228
|
+
],
|
|
229
|
+
"description": "Short summary, or null — branch on it."
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"path": "latestArticles[].imageUrl",
|
|
233
|
+
"availableIn": [
|
|
234
|
+
"section:articles"
|
|
235
|
+
],
|
|
236
|
+
"description": "Cover image URL, or null — always branch."
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"path": "latestArticles[].publishedAt",
|
|
240
|
+
"availableIn": [
|
|
241
|
+
"section:articles"
|
|
242
|
+
],
|
|
243
|
+
"description": "ISO-8601 publish time, or null — format with the date filter."
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"path": "latestArticles[].readingMinutes",
|
|
247
|
+
"availableIn": [
|
|
248
|
+
"section:articles"
|
|
249
|
+
],
|
|
250
|
+
"description": "Estimated reading minutes, or null."
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"path": "latestArticles[].categories",
|
|
254
|
+
"availableIn": [
|
|
255
|
+
"section:articles"
|
|
256
|
+
],
|
|
257
|
+
"description": "The article's category names (possibly empty) — treat as text."
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"path": "events[].id",
|
|
261
|
+
"availableIn": [
|
|
262
|
+
"page:events"
|
|
263
|
+
],
|
|
264
|
+
"description": "Stable event id."
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"path": "events[].name",
|
|
268
|
+
"availableIn": [
|
|
269
|
+
"page:events"
|
|
270
|
+
],
|
|
271
|
+
"description": "The event's name."
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"path": "events[].description",
|
|
275
|
+
"availableIn": [
|
|
276
|
+
"page:events"
|
|
277
|
+
],
|
|
278
|
+
"description": "Plain-text description, or null — branch on it."
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"path": "events[].registrationMode",
|
|
282
|
+
"availableIn": [
|
|
283
|
+
"page:events"
|
|
284
|
+
],
|
|
285
|
+
"description": "INFO (no sign-up), RSVP (free sign-up) or TICKETED (paid)."
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"path": "events[].startsAt",
|
|
289
|
+
"availableIn": [
|
|
290
|
+
"page:events"
|
|
291
|
+
],
|
|
292
|
+
"description": "ISO-8601 start — format with the date filter."
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"path": "events[].endsAt",
|
|
296
|
+
"availableIn": [
|
|
297
|
+
"page:events"
|
|
298
|
+
],
|
|
299
|
+
"description": "ISO-8601 end, or null."
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"path": "events[].venueName",
|
|
303
|
+
"availableIn": [
|
|
304
|
+
"page:events"
|
|
305
|
+
],
|
|
306
|
+
"description": "Venue name, or null (online events may have none)."
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"path": "events[].online",
|
|
310
|
+
"availableIn": [
|
|
311
|
+
"page:events"
|
|
312
|
+
],
|
|
313
|
+
"description": "True for online events."
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"path": "events[].imageUrl",
|
|
317
|
+
"availableIn": [
|
|
318
|
+
"page:events"
|
|
319
|
+
],
|
|
320
|
+
"description": "Promo image URL, or null — always branch."
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"path": "events[].onSale",
|
|
324
|
+
"availableIn": [
|
|
325
|
+
"page:events"
|
|
326
|
+
],
|
|
327
|
+
"description": "False before sales open."
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"path": "events[].soldOut",
|
|
331
|
+
"availableIn": [
|
|
332
|
+
"page:events"
|
|
333
|
+
],
|
|
334
|
+
"description": "True when no capacity remains."
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"path": "events[].priceFrom",
|
|
338
|
+
"availableIn": [
|
|
339
|
+
"page:events"
|
|
340
|
+
],
|
|
341
|
+
"description": "The cheapest ticket price (number), or null for free/INFO events."
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"path": "events[].currency",
|
|
345
|
+
"availableIn": [
|
|
346
|
+
"page:events"
|
|
347
|
+
],
|
|
348
|
+
"description": "ISO currency code for priceFrom, or null."
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"path": "events[].detailHref",
|
|
352
|
+
"availableIn": [
|
|
353
|
+
"page:events"
|
|
354
|
+
],
|
|
355
|
+
"description": "The canonical link to this event's detail view — always use this, never build URLs yourself."
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"path": "course",
|
|
359
|
+
"availableIn": [
|
|
360
|
+
"page:course"
|
|
361
|
+
],
|
|
362
|
+
"description": "The course this page addresses — a CURATED read-only view for display. The enrolment journey itself is the platform-owned course_enrol island; place it, never rebuild it."
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
"path": "course.id",
|
|
366
|
+
"availableIn": [
|
|
367
|
+
"page:course"
|
|
368
|
+
],
|
|
369
|
+
"description": "Stable course id."
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"path": "course.title",
|
|
373
|
+
"availableIn": [
|
|
374
|
+
"page:course"
|
|
375
|
+
],
|
|
376
|
+
"description": "The course's title."
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"path": "course.description",
|
|
380
|
+
"availableIn": [
|
|
381
|
+
"page:course"
|
|
382
|
+
],
|
|
383
|
+
"description": "Plain-text summary, or null — branch on it. Prefer aboutHtml for the body when present."
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"path": "course.aboutHtml",
|
|
387
|
+
"availableIn": [
|
|
388
|
+
"page:course"
|
|
389
|
+
],
|
|
390
|
+
"description": "The tenant-authored About page as SANITISED HTML (platform-sanitised on save; images resolved) — render with the raw filter inside your prose styles, or null when not written."
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"path": "course.imageUrl",
|
|
394
|
+
"availableIn": [
|
|
395
|
+
"page:course"
|
|
396
|
+
],
|
|
397
|
+
"description": "The MAIN image (hero) URL, or null — always branch."
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"path": "course.venue",
|
|
401
|
+
"availableIn": [
|
|
402
|
+
"page:course"
|
|
403
|
+
],
|
|
404
|
+
"description": "Venue display text, or null."
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"path": "course.audience",
|
|
408
|
+
"availableIn": [
|
|
409
|
+
"page:course"
|
|
410
|
+
],
|
|
411
|
+
"description": "EVERYONE, or CHILD for children-only courses (parents enrol their children)."
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
"path": "course.billingMode",
|
|
415
|
+
"availableIn": [
|
|
416
|
+
"page:course"
|
|
417
|
+
],
|
|
418
|
+
"description": "UPFRONT (one payment), TERM (committed term fee), or ROLLING (monthly with notice)."
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"path": "course.termStart",
|
|
422
|
+
"availableIn": [
|
|
423
|
+
"page:course"
|
|
424
|
+
],
|
|
425
|
+
"description": "ISO date the term starts, or null — format with the date filter."
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"path": "course.termEnd",
|
|
429
|
+
"availableIn": [
|
|
430
|
+
"page:course"
|
|
431
|
+
],
|
|
432
|
+
"description": "ISO date the term ends, or null."
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"path": "course.currency",
|
|
436
|
+
"availableIn": [
|
|
437
|
+
"page:course"
|
|
438
|
+
],
|
|
439
|
+
"description": "ISO currency code for priceFrom."
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
"path": "course.priceFrom",
|
|
443
|
+
"availableIn": [
|
|
444
|
+
"page:course"
|
|
445
|
+
],
|
|
446
|
+
"description": "The cheapest priced option (number), or null when every option is free."
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"path": "course.soldOut",
|
|
450
|
+
"availableIn": [
|
|
451
|
+
"page:course"
|
|
452
|
+
],
|
|
453
|
+
"description": "True when no option has places left (the island shows the standard note)."
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"path": "course.backHref",
|
|
457
|
+
"availableIn": [
|
|
458
|
+
"page:course"
|
|
459
|
+
],
|
|
460
|
+
"description": "The canonical link back to the courses listing — always use this."
|
|
423
461
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
"
|
|
427
|
-
|
|
428
|
-
"
|
|
429
|
-
"
|
|
430
|
-
"
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
"
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
"
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
"
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
462
|
+
],
|
|
463
|
+
"fixtures": {
|
|
464
|
+
"brand": {
|
|
465
|
+
"name": "Fixture Charity",
|
|
466
|
+
"tagline": "A fixture tagline.",
|
|
467
|
+
"logoUrl": null,
|
|
468
|
+
"logoType": "full",
|
|
469
|
+
"footerLogoUrl": null
|
|
470
|
+
},
|
|
471
|
+
"layout": {
|
|
472
|
+
"nav": {
|
|
473
|
+
"items": [
|
|
474
|
+
{
|
|
475
|
+
"label": "Home",
|
|
476
|
+
"href": "/",
|
|
477
|
+
"cta": false
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
"label": "About us",
|
|
481
|
+
"href": "/about",
|
|
482
|
+
"cta": false
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"label": "Events",
|
|
486
|
+
"href": "/events",
|
|
487
|
+
"cta": false
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
"label": "Services",
|
|
491
|
+
"href": "/services",
|
|
492
|
+
"cta": false,
|
|
493
|
+
"children": [
|
|
494
|
+
{
|
|
495
|
+
"label": "Food bank",
|
|
496
|
+
"href": "/services?service=food-bank"
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"label": "Youth club",
|
|
500
|
+
"href": "/services?service=youth-club"
|
|
501
|
+
}
|
|
502
|
+
]
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"label": "Donate",
|
|
506
|
+
"href": "/donate",
|
|
507
|
+
"cta": true
|
|
508
|
+
}
|
|
509
|
+
],
|
|
510
|
+
"footer": [
|
|
511
|
+
{ "label": "About us", "href": "/about" },
|
|
512
|
+
{ "label": "Contact", "href": "https://example.org/contact", "external": true },
|
|
513
|
+
{
|
|
514
|
+
"label": "Our work",
|
|
515
|
+
"href": "#",
|
|
516
|
+
"children": [
|
|
517
|
+
{ "label": "Food bank", "href": "/services?service=food-bank" }
|
|
518
|
+
]
|
|
519
|
+
}
|
|
520
|
+
],
|
|
521
|
+
"derived": [
|
|
522
|
+
{ "label": "Home", "href": "/", "cta": false },
|
|
523
|
+
{ "label": "About us", "href": "/about", "cta": false },
|
|
524
|
+
{ "label": "Events", "href": "/events", "cta": false },
|
|
525
|
+
{ "label": "Donate", "href": "/donate", "cta": true }
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
"socials": [
|
|
529
|
+
{
|
|
530
|
+
"platform": "facebook",
|
|
531
|
+
"url": "https://facebook.com/fixture",
|
|
532
|
+
"iconSvg": "<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"10\"/></svg>"
|
|
533
|
+
}
|
|
534
|
+
],
|
|
535
|
+
"worship": {
|
|
536
|
+
"times": [
|
|
537
|
+
{
|
|
538
|
+
"name": "Fajr",
|
|
539
|
+
"begins": "03:20",
|
|
540
|
+
"congregation": "04:00"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"name": "Zuhr",
|
|
544
|
+
"begins": "13:11",
|
|
545
|
+
"congregation": "13:30"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"name": "Asr",
|
|
549
|
+
"begins": "18:30",
|
|
550
|
+
"congregation": "19:00"
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
"name": "Maghrib",
|
|
554
|
+
"begins": "21:04",
|
|
555
|
+
"congregation": "21:04"
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
"name": "Isha",
|
|
559
|
+
"begins": "22:12",
|
|
560
|
+
"congregation": "22:30"
|
|
561
|
+
}
|
|
562
|
+
],
|
|
563
|
+
"beginsLabel": "Begins",
|
|
564
|
+
"congregationLabel": "Jama'at",
|
|
565
|
+
"note": "Jum'a 13:15 & 14:15",
|
|
566
|
+
"href": "/services?service=prayer-times",
|
|
567
|
+
"today": "24 July 2026",
|
|
568
|
+
"todayAlt": "11 Safar 1448"
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
"pages": {
|
|
572
|
+
"events": {
|
|
573
|
+
"events": [
|
|
574
|
+
{
|
|
575
|
+
"id": "11111111-1111-1111-1111-111111111111",
|
|
576
|
+
"name": "Summer Gala",
|
|
577
|
+
"description": "An evening of music and giving.",
|
|
578
|
+
"registrationMode": "TICKETED",
|
|
579
|
+
"startsAt": "2030-08-15T18:00:00Z",
|
|
580
|
+
"endsAt": null,
|
|
581
|
+
"venueName": "Town Hall",
|
|
582
|
+
"online": false,
|
|
583
|
+
"imageUrl": null,
|
|
584
|
+
"onSale": true,
|
|
585
|
+
"soldOut": false,
|
|
586
|
+
"priceFrom": 10.0,
|
|
587
|
+
"currency": "GBP",
|
|
588
|
+
"detailHref": "/events?event=11111111-1111-1111-1111-111111111111"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"id": "22222222-2222-2222-2222-222222222222",
|
|
592
|
+
"name": "Coffee Morning",
|
|
593
|
+
"description": null,
|
|
594
|
+
"registrationMode": "RSVP",
|
|
595
|
+
"startsAt": "2030-08-01T10:00:00Z",
|
|
596
|
+
"endsAt": "2030-08-01T12:00:00Z",
|
|
597
|
+
"venueName": null,
|
|
598
|
+
"online": true,
|
|
599
|
+
"imageUrl": null,
|
|
600
|
+
"onSale": true,
|
|
601
|
+
"soldOut": true,
|
|
602
|
+
"priceFrom": null,
|
|
603
|
+
"currency": null,
|
|
604
|
+
"detailHref": "/events?event=22222222-2222-2222-2222-222222222222"
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
"id": "33333333-3333-3333-3333-333333333333",
|
|
608
|
+
"name": "Open Day",
|
|
609
|
+
"description": "Drop in and meet the team.",
|
|
610
|
+
"registrationMode": "INFO",
|
|
611
|
+
"startsAt": "2030-09-01T09:00:00Z",
|
|
612
|
+
"endsAt": null,
|
|
613
|
+
"venueName": "Community Centre",
|
|
614
|
+
"online": false,
|
|
615
|
+
"imageUrl": null,
|
|
616
|
+
"onSale": true,
|
|
617
|
+
"soldOut": false,
|
|
618
|
+
"priceFrom": null,
|
|
619
|
+
"currency": null,
|
|
620
|
+
"detailHref": "/events?event=33333333-3333-3333-3333-333333333333"
|
|
621
|
+
}
|
|
622
|
+
]
|
|
623
|
+
},
|
|
624
|
+
"course": {
|
|
625
|
+
"course": {
|
|
626
|
+
"id": "33333333-3333-3333-3333-333333333333",
|
|
627
|
+
"title": "Junior Athletics",
|
|
628
|
+
"description": "Weekly athletics for children aged 7–12.",
|
|
629
|
+
"aboutHtml": "<h2>What we do</h2><p>Track and field fundamentals in a friendly, coached setting.</p><ul><li>Warm-ups and drills</li><li>Sprints, jumps and throws</li></ul>",
|
|
630
|
+
"imageUrl": null,
|
|
631
|
+
"venue": "King's Park track",
|
|
632
|
+
"audience": "CHILD",
|
|
633
|
+
"billingMode": "ROLLING",
|
|
634
|
+
"termStart": null,
|
|
635
|
+
"termEnd": null,
|
|
636
|
+
"currency": "GBP",
|
|
637
|
+
"priceFrom": 15.0,
|
|
638
|
+
"soldOut": false,
|
|
639
|
+
"backHref": "/courses"
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
},
|
|
643
|
+
"sections": {
|
|
644
|
+
"events": {
|
|
645
|
+
"events": [
|
|
646
|
+
{
|
|
647
|
+
"id": "22222222-2222-2222-2222-222222222222",
|
|
648
|
+
"name": "Fixture Lantern Gala",
|
|
649
|
+
"description": "An evening fixture event.",
|
|
650
|
+
"registrationMode": "TICKETED",
|
|
651
|
+
"startsAt": "2030-09-20T19:00:00Z",
|
|
652
|
+
"endsAt": null,
|
|
653
|
+
"venueName": "Fixture Hall",
|
|
654
|
+
"online": false,
|
|
655
|
+
"imageUrl": null,
|
|
656
|
+
"onSale": true,
|
|
657
|
+
"soldOut": false,
|
|
658
|
+
"priceFrom": 12.5,
|
|
659
|
+
"currency": "GBP",
|
|
660
|
+
"detailHref": "/events?event=22222222-2222-2222-2222-222222222222"
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"id": "44444444-4444-4444-4444-444444444444",
|
|
664
|
+
"name": "Fixture Riverside Concert",
|
|
665
|
+
"description": "An evening fixture event.",
|
|
666
|
+
"registrationMode": "TICKETED",
|
|
667
|
+
"startsAt": "2030-09-20T19:00:00Z",
|
|
668
|
+
"endsAt": null,
|
|
669
|
+
"venueName": "Fixture Hall",
|
|
670
|
+
"online": false,
|
|
671
|
+
"imageUrl": null,
|
|
672
|
+
"onSale": true,
|
|
673
|
+
"soldOut": false,
|
|
674
|
+
"priceFrom": 12.5,
|
|
675
|
+
"currency": "GBP",
|
|
676
|
+
"detailHref": "/events?event=44444444-4444-4444-4444-444444444444"
|
|
677
|
+
}
|
|
678
|
+
]
|
|
679
|
+
},
|
|
680
|
+
"whatsOn": {
|
|
681
|
+
"infoEvents": [
|
|
682
|
+
{
|
|
683
|
+
"id": "33333333-3333-3333-3333-333333333333",
|
|
684
|
+
"name": "Fixture Open Morning",
|
|
685
|
+
"description": "An evening fixture event.",
|
|
686
|
+
"registrationMode": "INFO",
|
|
687
|
+
"startsAt": "2030-09-20T19:00:00Z",
|
|
688
|
+
"endsAt": null,
|
|
689
|
+
"venueName": "Fixture Hall",
|
|
690
|
+
"online": false,
|
|
691
|
+
"imageUrl": null,
|
|
692
|
+
"onSale": true,
|
|
693
|
+
"soldOut": false,
|
|
694
|
+
"priceFrom": null,
|
|
695
|
+
"currency": null,
|
|
696
|
+
"detailHref": "/events?event=33333333-3333-3333-3333-333333333333"
|
|
697
|
+
}
|
|
698
|
+
]
|
|
699
|
+
},
|
|
700
|
+
"articles": {
|
|
701
|
+
"latestArticles": [
|
|
702
|
+
{
|
|
703
|
+
"title": "Fixture Winter Diary",
|
|
704
|
+
"href": "/articles/fixture-winter-diary",
|
|
705
|
+
"excerpt": "A fixture article summary.",
|
|
706
|
+
"imageUrl": null,
|
|
707
|
+
"publishedAt": "2030-01-05T09:00:00Z",
|
|
708
|
+
"readingMinutes": 4,
|
|
709
|
+
"categories": [
|
|
710
|
+
"News"
|
|
711
|
+
]
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
"title": "Fixture Spring Appeal Notes",
|
|
715
|
+
"href": "/articles/fixture-spring-appeal-notes",
|
|
716
|
+
"excerpt": "A fixture article summary.",
|
|
717
|
+
"imageUrl": null,
|
|
718
|
+
"publishedAt": "2030-01-05T09:00:00Z",
|
|
719
|
+
"readingMinutes": 4,
|
|
720
|
+
"categories": [
|
|
721
|
+
"News"
|
|
722
|
+
]
|
|
723
|
+
}
|
|
724
|
+
]
|
|
725
|
+
}
|
|
530
726
|
}
|
|
531
|
-
}
|
|
532
727
|
}
|
|
533
|
-
}
|
|
534
728
|
}
|