ferst-core 0.7.5 → 0.7.7
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/bin/ferst-modules.mjs +91 -0
- package/cms/config.template.yml +13 -0
- package/components/BlockRenderer.astro +2 -0
- package/components/ProseParts.astro +26 -0
- package/components/SiteFooter.astro +52 -1
- package/components/SiteHeader.astro +1246 -1243
- package/components/blocks/Prose.astro +12 -17
- package/components/recipes/Accordion.astro +3 -7
- package/components/recipes/Contacts.astro +3 -3
- package/components/recipes/Document.astro +7 -11
- package/components/recipes/Documents.astro +2 -2
- package/components/recipes/Form.astro +30 -0
- package/components/recipes/MediaText.astro +88 -92
- package/components/recipes/Steps.astro +121 -120
- package/components/recipes/Table.astro +3 -2
- package/components/recipes/Video.astro +1 -1
- package/content/blocks.ts +917 -887
- package/content/schemas.ts +5 -0
- package/fonts/OFL.txt +287 -0
- package/fonts/inter-latin-400-normal.woff2 +0 -0
- package/fonts/inter-latin-500-normal.woff2 +0 -0
- package/fonts/inter-latin-600-normal.woff2 +0 -0
- package/fonts/playfair-display-latin-700-normal.woff2 +0 -0
- package/fonts/poppins-latin-300-normal.woff2 +0 -0
- package/fonts/poppins-latin-400-normal.woff2 +0 -0
- package/fonts/poppins-latin-500-normal.woff2 +0 -0
- package/fonts/poppins-latin-600-normal.woff2 +0 -0
- package/fonts/poppins-latin-700-normal.woff2 +0 -0
- package/integration.mjs +41 -1
- package/layouts/Base.astro +1 -0
- package/lib/forms.ts +57 -0
- package/lib/icons.ts +10 -0
- package/lib/links.ts +24 -22
- package/lib/nav.ts +12 -0
- package/lib/siteSettings.ts +2 -1
- package/package.json +5 -3
package/content/schemas.ts
CHANGED
|
@@ -90,6 +90,11 @@ export const navbarSettingsSchema = z.object({
|
|
|
90
90
|
export const footerSettingsSchema = z.object({
|
|
91
91
|
/** Footer legal/info nav. Empty by default — every client defines its own. */
|
|
92
92
|
footer: z.array(navLinkSchema).default([]),
|
|
93
|
+
/** Headed footer columns for reference material (policies, safeguarding, documents,
|
|
94
|
+
* forms) — where it belongs, so the main menu stays short and clear. */
|
|
95
|
+
groups: z
|
|
96
|
+
.array(z.object({ heading: z.string(), links: z.array(navLinkSchema).min(1) }))
|
|
97
|
+
.default([]),
|
|
93
98
|
});
|
|
94
99
|
|
|
95
100
|
/**
|
package/fonts/OFL.txt
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
Fonts in this folder are distributed under the SIL Open Font License, Version 1.1.
|
|
2
|
+
Files taken unmodified from Fontsource (https://fontsource.org): @fontsource/inter, @fontsource/playfair-display and @fontsource/poppins 5.3.0.
|
|
3
|
+
|
|
4
|
+
==================== inter ====================
|
|
5
|
+
Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter) Inter-Italic[opsz,wght].ttf: Copyright 2016 The Inter Project Authors (https://github.com/rsms/inter)
|
|
6
|
+
|
|
7
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
8
|
+
This license is copied below, and is also available with a FAQ at:
|
|
9
|
+
http://scripts.sil.org/OFL
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
-----------------------------------------------------------
|
|
13
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
14
|
+
-----------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
PREAMBLE
|
|
17
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
18
|
+
development of collaborative font projects, to support the font creation
|
|
19
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
20
|
+
open framework in which fonts may be shared and improved in partnership
|
|
21
|
+
with others.
|
|
22
|
+
|
|
23
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
24
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
25
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
26
|
+
redistributed and/or sold with any software provided that any reserved
|
|
27
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
28
|
+
however, cannot be released under any other type of license. The
|
|
29
|
+
requirement for fonts to remain under this license does not apply
|
|
30
|
+
to any document created using the fonts or their derivatives.
|
|
31
|
+
|
|
32
|
+
DEFINITIONS
|
|
33
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
34
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
35
|
+
include source files, build scripts and documentation.
|
|
36
|
+
|
|
37
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
38
|
+
copyright statement(s).
|
|
39
|
+
|
|
40
|
+
"Original Version" refers to the collection of Font Software components as
|
|
41
|
+
distributed by the Copyright Holder(s).
|
|
42
|
+
|
|
43
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
44
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
45
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
46
|
+
new environment.
|
|
47
|
+
|
|
48
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
49
|
+
writer or other person who contributed to the Font Software.
|
|
50
|
+
|
|
51
|
+
PERMISSION & CONDITIONS
|
|
52
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
53
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
54
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
55
|
+
Software, subject to the following conditions:
|
|
56
|
+
|
|
57
|
+
1) Neither the Font Software nor any of its individual components,
|
|
58
|
+
in Original or Modified Versions, may be sold by itself.
|
|
59
|
+
|
|
60
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
61
|
+
redistributed and/or sold with any software, provided that each copy
|
|
62
|
+
contains the above copyright notice and this license. These can be
|
|
63
|
+
included either as stand-alone text files, human-readable headers or
|
|
64
|
+
in the appropriate machine-readable metadata fields within text or
|
|
65
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
66
|
+
|
|
67
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
68
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
69
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
70
|
+
presented to the users.
|
|
71
|
+
|
|
72
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
73
|
+
Software shall not be used to promote, endorse or advertise any
|
|
74
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
75
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
76
|
+
permission.
|
|
77
|
+
|
|
78
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
79
|
+
must be distributed entirely under this license, and must not be
|
|
80
|
+
distributed under any other license. The requirement for fonts to
|
|
81
|
+
remain under this license does not apply to any document created
|
|
82
|
+
using the Font Software.
|
|
83
|
+
|
|
84
|
+
TERMINATION
|
|
85
|
+
This license becomes null and void if any of the above conditions are
|
|
86
|
+
not met.
|
|
87
|
+
|
|
88
|
+
DISCLAIMER
|
|
89
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
90
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
91
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
92
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
93
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
94
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
95
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
96
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
97
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
98
|
+
|
|
99
|
+
==================== playfair-display ====================
|
|
100
|
+
Copyright 2017 The Playfair Display Project Authors (https://github.com/clauseggers/Playfair-Display), with Reserved Font Name "Playfair Display". PlayfairDisplay-Italic[wght].ttf: Copyright 2017 The Playfair Display Project Authors (https://github.com/clauseggers/Playfair-Display), with Reserved Font Name "Playfair Display".
|
|
101
|
+
|
|
102
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
103
|
+
This license is copied below, and is also available with a FAQ at:
|
|
104
|
+
http://scripts.sil.org/OFL
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
-----------------------------------------------------------
|
|
108
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
109
|
+
-----------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
PREAMBLE
|
|
112
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
113
|
+
development of collaborative font projects, to support the font creation
|
|
114
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
115
|
+
open framework in which fonts may be shared and improved in partnership
|
|
116
|
+
with others.
|
|
117
|
+
|
|
118
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
119
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
120
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
121
|
+
redistributed and/or sold with any software provided that any reserved
|
|
122
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
123
|
+
however, cannot be released under any other type of license. The
|
|
124
|
+
requirement for fonts to remain under this license does not apply
|
|
125
|
+
to any document created using the fonts or their derivatives.
|
|
126
|
+
|
|
127
|
+
DEFINITIONS
|
|
128
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
129
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
130
|
+
include source files, build scripts and documentation.
|
|
131
|
+
|
|
132
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
133
|
+
copyright statement(s).
|
|
134
|
+
|
|
135
|
+
"Original Version" refers to the collection of Font Software components as
|
|
136
|
+
distributed by the Copyright Holder(s).
|
|
137
|
+
|
|
138
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
139
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
140
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
141
|
+
new environment.
|
|
142
|
+
|
|
143
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
144
|
+
writer or other person who contributed to the Font Software.
|
|
145
|
+
|
|
146
|
+
PERMISSION & CONDITIONS
|
|
147
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
148
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
149
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
150
|
+
Software, subject to the following conditions:
|
|
151
|
+
|
|
152
|
+
1) Neither the Font Software nor any of its individual components,
|
|
153
|
+
in Original or Modified Versions, may be sold by itself.
|
|
154
|
+
|
|
155
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
156
|
+
redistributed and/or sold with any software, provided that each copy
|
|
157
|
+
contains the above copyright notice and this license. These can be
|
|
158
|
+
included either as stand-alone text files, human-readable headers or
|
|
159
|
+
in the appropriate machine-readable metadata fields within text or
|
|
160
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
161
|
+
|
|
162
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
163
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
164
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
165
|
+
presented to the users.
|
|
166
|
+
|
|
167
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
168
|
+
Software shall not be used to promote, endorse or advertise any
|
|
169
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
170
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
171
|
+
permission.
|
|
172
|
+
|
|
173
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
174
|
+
must be distributed entirely under this license, and must not be
|
|
175
|
+
distributed under any other license. The requirement for fonts to
|
|
176
|
+
remain under this license does not apply to any document created
|
|
177
|
+
using the Font Software.
|
|
178
|
+
|
|
179
|
+
TERMINATION
|
|
180
|
+
This license becomes null and void if any of the above conditions are
|
|
181
|
+
not met.
|
|
182
|
+
|
|
183
|
+
DISCLAIMER
|
|
184
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
185
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
186
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
187
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
188
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
189
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
190
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
191
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
192
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
193
|
+
|
|
194
|
+
==================== poppins ====================
|
|
195
|
+
Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-ThinItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-ExtraLight.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-ExtraLightItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-Light.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-LightItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-Regular.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-Italic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-Medium.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-MediumItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-SemiBold.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-SemiBoldItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-Bold.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-BoldItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-ExtraBold.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-ExtraBoldItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-Black.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) Poppins-BlackItalic.ttf: Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins)
|
|
196
|
+
|
|
197
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
198
|
+
This license is copied below, and is also available with a FAQ at:
|
|
199
|
+
http://scripts.sil.org/OFL
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
-----------------------------------------------------------
|
|
203
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
204
|
+
-----------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
PREAMBLE
|
|
207
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
208
|
+
development of collaborative font projects, to support the font creation
|
|
209
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
210
|
+
open framework in which fonts may be shared and improved in partnership
|
|
211
|
+
with others.
|
|
212
|
+
|
|
213
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
214
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
215
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
216
|
+
redistributed and/or sold with any software provided that any reserved
|
|
217
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
218
|
+
however, cannot be released under any other type of license. The
|
|
219
|
+
requirement for fonts to remain under this license does not apply
|
|
220
|
+
to any document created using the fonts or their derivatives.
|
|
221
|
+
|
|
222
|
+
DEFINITIONS
|
|
223
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
224
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
225
|
+
include source files, build scripts and documentation.
|
|
226
|
+
|
|
227
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
228
|
+
copyright statement(s).
|
|
229
|
+
|
|
230
|
+
"Original Version" refers to the collection of Font Software components as
|
|
231
|
+
distributed by the Copyright Holder(s).
|
|
232
|
+
|
|
233
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
234
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
235
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
236
|
+
new environment.
|
|
237
|
+
|
|
238
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
239
|
+
writer or other person who contributed to the Font Software.
|
|
240
|
+
|
|
241
|
+
PERMISSION & CONDITIONS
|
|
242
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
243
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
244
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
245
|
+
Software, subject to the following conditions:
|
|
246
|
+
|
|
247
|
+
1) Neither the Font Software nor any of its individual components,
|
|
248
|
+
in Original or Modified Versions, may be sold by itself.
|
|
249
|
+
|
|
250
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
251
|
+
redistributed and/or sold with any software, provided that each copy
|
|
252
|
+
contains the above copyright notice and this license. These can be
|
|
253
|
+
included either as stand-alone text files, human-readable headers or
|
|
254
|
+
in the appropriate machine-readable metadata fields within text or
|
|
255
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
256
|
+
|
|
257
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
258
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
259
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
260
|
+
presented to the users.
|
|
261
|
+
|
|
262
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
263
|
+
Software shall not be used to promote, endorse or advertise any
|
|
264
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
265
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
266
|
+
permission.
|
|
267
|
+
|
|
268
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
269
|
+
must be distributed entirely under this license, and must not be
|
|
270
|
+
distributed under any other license. The requirement for fonts to
|
|
271
|
+
remain under this license does not apply to any document created
|
|
272
|
+
using the Font Software.
|
|
273
|
+
|
|
274
|
+
TERMINATION
|
|
275
|
+
This license becomes null and void if any of the above conditions are
|
|
276
|
+
not met.
|
|
277
|
+
|
|
278
|
+
DISCLAIMER
|
|
279
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
280
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
281
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
282
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
283
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
284
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
285
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
286
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
287
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/integration.mjs
CHANGED
|
@@ -27,7 +27,45 @@
|
|
|
27
27
|
* the site has its own `src/pages/cookie-policy.astro`.
|
|
28
28
|
* @returns {import('astro').AstroIntegration}
|
|
29
29
|
*/
|
|
30
|
-
import { existsSync } from 'node:fs';
|
|
30
|
+
import { copyFileSync, createReadStream, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
|
31
|
+
|
|
32
|
+
/** The self-hosted fonts the engine's CSS requests (/fonts/*.woff2), shipped in the package. */
|
|
33
|
+
const FONTS_DIR = new URL('./fonts/', import.meta.url);
|
|
34
|
+
const FONT_URL = /^\/fonts\/([a-z0-9-]+\.woff2)(?:\?.*)?$/;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* ferstFonts() — serves the engine's self-hosted fonts in `astro dev` and copies them into
|
|
38
|
+
* every build's `/fonts/`. Included in ferst(); usable on its own (the showcase). A file
|
|
39
|
+
* the site already has in its own `public/fonts/` is never overwritten.
|
|
40
|
+
* @returns {import('astro').AstroIntegration}
|
|
41
|
+
*/
|
|
42
|
+
export function ferstFonts() {
|
|
43
|
+
return {
|
|
44
|
+
name: 'ferst-fonts',
|
|
45
|
+
hooks: {
|
|
46
|
+
'astro:server:setup': ({ server }) => {
|
|
47
|
+
server.middlewares.use((req, res, next) => {
|
|
48
|
+
const m = req.url && req.url.match(FONT_URL);
|
|
49
|
+
if (!m) return next();
|
|
50
|
+
const file = new URL(m[1], FONTS_DIR);
|
|
51
|
+
if (!existsSync(file)) return next();
|
|
52
|
+
res.setHeader('Content-Type', 'font/woff2');
|
|
53
|
+
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
54
|
+
createReadStream(file).pipe(res);
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
'astro:build:done': async ({ dir }) => {
|
|
58
|
+
const out = new URL('fonts/', dir);
|
|
59
|
+
mkdirSync(out, { recursive: true });
|
|
60
|
+
for (const name of readdirSync(FONTS_DIR)) {
|
|
61
|
+
if (!name.endsWith('.woff2')) continue;
|
|
62
|
+
const dest = new URL(name, out);
|
|
63
|
+
if (!existsSync(dest)) copyFileSync(new URL(name, FONTS_DIR), dest);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
31
69
|
|
|
32
70
|
export default function ferst(options = {}) {
|
|
33
71
|
const { calendar = true, blog = true, cookiePolicy = true } = options;
|
|
@@ -78,6 +116,8 @@ export default function ferst(options = {}) {
|
|
|
78
116
|
});
|
|
79
117
|
}
|
|
80
118
|
},
|
|
119
|
+
// The engine's self-hosted fonts: served in dev, copied into every build.
|
|
120
|
+
...ferstFonts().hooks,
|
|
81
121
|
},
|
|
82
122
|
};
|
|
83
123
|
}
|
package/layouts/Base.astro
CHANGED
|
@@ -215,6 +215,7 @@ const metaDescription = description ?? identity.description;
|
|
|
215
215
|
<SiteFooter
|
|
216
216
|
facebookUrl={contact.facebookUrl}
|
|
217
217
|
footerLinks={navigation.footer}
|
|
218
|
+
groups={navigation.footerGroups}
|
|
218
219
|
cta={navigation.cta}
|
|
219
220
|
footerClass={footerClass}
|
|
220
221
|
shortName={identity.shortName}
|
package/lib/forms.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A form placed by id (the `form` block) is read from the Ferst platform at build time, so
|
|
3
|
+
* a change made to it in the portal reaches the site on its next build — no pasted copy of
|
|
4
|
+
* its fields to keep in step. A missing form or an unreachable platform fails the build:
|
|
5
|
+
* better the last good deploy stays live than a form that can't be sent goes out.
|
|
6
|
+
*/
|
|
7
|
+
export interface FormField {
|
|
8
|
+
name: string;
|
|
9
|
+
label: string;
|
|
10
|
+
type?: 'text' | 'email' | 'tel' | 'textarea';
|
|
11
|
+
required?: boolean;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface FormDefinition {
|
|
16
|
+
name: string;
|
|
17
|
+
submitLabel: string;
|
|
18
|
+
fields: FormField[];
|
|
19
|
+
/** Where the browser posts the form. */
|
|
20
|
+
action: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type FetchFn = (input: string, init?: RequestInit) => Promise<Response>;
|
|
24
|
+
|
|
25
|
+
const cache = new Map<string, Promise<FormDefinition>>();
|
|
26
|
+
|
|
27
|
+
export function loadFormDefinition(id: string, opts: { base: string; fetch?: FetchFn }): Promise<FormDefinition> {
|
|
28
|
+
const key = `${opts.base}|${id}`;
|
|
29
|
+
let hit = cache.get(key);
|
|
30
|
+
if (!hit) {
|
|
31
|
+
hit = fetchDefinition(id, opts.base, opts.fetch ?? fetch);
|
|
32
|
+
cache.set(key, hit);
|
|
33
|
+
hit.catch(() => cache.delete(key)); // a failure is retried by the next caller
|
|
34
|
+
}
|
|
35
|
+
return hit;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function fetchDefinition(id: string, base: string, fetchFn: FetchFn): Promise<FormDefinition> {
|
|
39
|
+
const url = `${base}/forms/${encodeURIComponent(id)}`;
|
|
40
|
+
let res: Response;
|
|
41
|
+
try {
|
|
42
|
+
res = await fetchFn(url, { headers: { Accept: 'application/json' } });
|
|
43
|
+
} catch (e) {
|
|
44
|
+
throw new Error(`Form block: couldn’t reach the Ferst platform for form "${id}" (${url}): ${e instanceof Error ? e.message : String(e)}`);
|
|
45
|
+
}
|
|
46
|
+
if (res.status === 404) {
|
|
47
|
+
throw new Error(`Form block: form "${id}" was not found — it may have been archived. Check the id in the portal (Forms), or run \`npx ferst-modules\` to list this site's forms.`);
|
|
48
|
+
}
|
|
49
|
+
if (!res.ok) throw new Error(`Form block: the Ferst platform answered ${res.status} for form "${id}" (${url}).`);
|
|
50
|
+
const def = (await res.json()) as { name: string; submit_label?: string; fields?: FormField[] };
|
|
51
|
+
return {
|
|
52
|
+
name: def.name,
|
|
53
|
+
submitLabel: def.submit_label || 'Send',
|
|
54
|
+
fields: def.fields ?? [],
|
|
55
|
+
action: `${base}/forms/${encodeURIComponent(id)}/submit`,
|
|
56
|
+
};
|
|
57
|
+
}
|
package/lib/icons.ts
CHANGED
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
* dropped in favour of the entries already here.
|
|
17
17
|
*/
|
|
18
18
|
export const ICONS: Record<string, string> = {
|
|
19
|
+
// ── Shapes added in 0.7.6 (named for what they depict, not for a sector) ──
|
|
20
|
+
steeple: '<path d="M12 2v3M10.5 3.5h3"></path><path d="M12 5 8 10v11h8V10z"></path><path d="M8 13l-4 2.5V21M16 13l4 2.5V21M3 21h18"></path><path d="M11 21v-3.5a1 1 0 0 1 2 0V21"></path>',
|
|
21
|
+
cross: '<path d="M12 3v18M7 8h10"></path>',
|
|
22
|
+
chalice: '<path d="M7 3h10c0 4.2-2.2 7-5 7S7 7.2 7 3z"></path><path d="M12 10v7M8.5 21h7M9.5 17h5"></path>',
|
|
23
|
+
shell: '<path d="M12 20 4.2 9.5a8.5 8.5 0 0 1 15.6 0z"></path><path d="M12 20 7.4 6.6M12 20V4.6M12 20l4.6-13.4"></path>',
|
|
24
|
+
jar: '<path d="M9.5 3h5M10.5 3v2.5L8 8.5v10a2.5 2.5 0 0 0 2.5 2.5h3a2.5 2.5 0 0 0 2.5-2.5v-10l-2.5-3V3"></path><path d="M8 13h8"></path>',
|
|
25
|
+
rings: '<circle cx="9" cy="15" r="5"></circle><circle cx="15" cy="15" r="5"></circle><path d="m15 4.5 1.6 1.6L15 7.7l-1.6-1.6z"></path><path d="M15 7.7V10"></path>',
|
|
26
|
+
stole: '<path d="M8.5 3c.4 6 .2 12-1.5 18M15.5 3c-.4 6-.2 12 1.5 18"></path><path d="M8.5 3c1.8 1.6 5.2 1.6 7 0"></path><path d="M7.4 17.5h2.4M14.2 17.5h2.4"></path>',
|
|
27
|
+
candle: '<path d="M12 3c1.1 1.4 1.6 2.4 1.6 3.2a1.6 1.6 0 0 1-3.2 0c0-.8.5-1.8 1.6-3.2z"></path><rect x="9" y="10" width="6" height="11" rx="1"></rect>',
|
|
28
|
+
|
|
19
29
|
landmark: '<path d="M12 3v4M9 7h6M6 21V10l6-4 6 4v11M6 21h12M10 21v-5h4v5"></path>',
|
|
20
30
|
canopy: '<polygon points="12 3 3 9 21 9"></polygon><line x1="4" y1="9" x2="4" y2="19"></line><line x1="9" y1="9" x2="9" y2="19"></line><line x1="15" y1="9" x2="15" y2="19"></line><line x1="20" y1="9" x2="20" y2="19"></line><line x1="2" y1="22" x2="22" y2="22"></line>',
|
|
21
31
|
drop: '<path d="M12 3c3 4 6 8.5 6 12a6 6 0 1 1-12 0c0-3.5 3-8 6-12z"></path>',
|
package/lib/links.ts
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The icon a link deserves, read from the link itself — so an editor writes a phone
|
|
3
|
-
* number, an email or a web address and the row shows the right symbol without choosing.
|
|
4
|
-
*/
|
|
5
|
-
import type { IconKey } from './icons';
|
|
6
|
-
|
|
7
|
-
export function linkIcon(href: string): IconKey {
|
|
8
|
-
if (/^tel:/i.test(href)) return 'phone';
|
|
9
|
-
if (/^mailto:/i.test(href)) return 'email';
|
|
10
|
-
if (/^https?:\/\//i.test(href)) return 'globe';
|
|
11
|
-
return 'arrow';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** A tel: link from a number as an editor types it (spaces, brackets, a "(0)" dropped). */
|
|
15
|
-
export function telHref(phone: string): string {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The icon a link deserves, read from the link itself — so an editor writes a phone
|
|
3
|
+
* number, an email or a web address and the row shows the right symbol without choosing.
|
|
4
|
+
*/
|
|
5
|
+
import type { IconKey } from './icons';
|
|
6
|
+
|
|
7
|
+
export function linkIcon(href: string): IconKey {
|
|
8
|
+
if (/^tel:/i.test(href)) return 'phone';
|
|
9
|
+
if (/^mailto:/i.test(href)) return 'email';
|
|
10
|
+
if (/^https?:\/\//i.test(href)) return 'globe';
|
|
11
|
+
return 'arrow';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** A tel: link from a number as an editor types it (spaces, brackets, a "(0)" dropped). */
|
|
15
|
+
export function telHref(phone: string): string {
|
|
16
|
+
// An extension ("ext. 204", "x204", "(extension 204)") is shown but never dialled.
|
|
17
|
+
const number = phone.replace(/\(?\s*(?:ext\.?|extension|x)\s*\d+\s*\)?\s*$/i, '');
|
|
18
|
+
return 'tel:' + number.replace(/\(0\)/g, '').replace(/[^\d+]/g, '');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A mailto: link, with an optional pre-filled subject. */
|
|
22
|
+
export function mailtoHref(email: string, subject?: string): string {
|
|
23
|
+
return `mailto:${email}${subject ? `?subject=${encodeURIComponent(subject)}` : ''}`;
|
|
24
|
+
}
|
package/lib/nav.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The header's call-to-action button (navbarSettings.cta) wins over a plain menu link to
|
|
3
|
+
* the same place, so a site never shows Contact twice (once as a link, once as the button).
|
|
4
|
+
* Migrated sites' old menus almost always carry a Contact link. Pure.
|
|
5
|
+
*/
|
|
6
|
+
const norm = (href: string) => href.replace(/\/+$/, '') || '/';
|
|
7
|
+
|
|
8
|
+
export function navWithoutCta<T extends { href: string }>(links: T[], cta: { href: string } | null | undefined): T[] {
|
|
9
|
+
if (!cta) return links;
|
|
10
|
+
const target = norm(cta.href);
|
|
11
|
+
return links.filter((l) => norm(l.href) !== target);
|
|
12
|
+
}
|
package/lib/siteSettings.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
|
|
28
28
|
export type LoadedSiteSettings = SiteSettings &
|
|
29
29
|
LogoSettings & {
|
|
30
|
-
navigation: { primary: NavLink[]; footer: NavLink[]; dropdown?: NavGroup; cta: { label: string; href: string } | null };
|
|
30
|
+
navigation: { primary: NavLink[]; footer: NavLink[]; footerGroups: Array<{ heading: string; links: NavLink[] }>; dropdown?: NavGroup; cta: { label: string; href: string } | null };
|
|
31
31
|
/** Client-provided design-token overrides (empty objects if none). */
|
|
32
32
|
theme: ThemeSettings;
|
|
33
33
|
};
|
|
@@ -51,6 +51,7 @@ export async function loadSiteSettings(): Promise<LoadedSiteSettings> {
|
|
|
51
51
|
navigation: {
|
|
52
52
|
primary: navbarSettingsSchema.parse(navbarEntry?.data ?? {}).primary,
|
|
53
53
|
footer: footerSettingsSchema.parse(footerEntry?.data ?? {}).footer,
|
|
54
|
+
footerGroups: footerSettingsSchema.parse(footerEntry?.data ?? {}).groups,
|
|
54
55
|
dropdown: navbarSettingsSchema.parse(navbarEntry?.data ?? {}).dropdown,
|
|
55
56
|
cta: navbarSettingsSchema.parse(navbarEntry?.data ?? {}).cta,
|
|
56
57
|
},
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ferst-core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Ferst Core
|
|
5
|
+
"description": "Ferst Core \u2014 the shared, brand-agnostic client-site system: Astro components, layouts, content schemas, the layered config resolver, and a neutral styling architecture that every client overrides.",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
7
7
|
"author": "MyAI4 Ltd (https://ferst.co.uk)",
|
|
8
8
|
"homepage": "https://ferst.co.uk",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"routes",
|
|
43
43
|
"utils",
|
|
44
44
|
"styles",
|
|
45
|
+
"fonts",
|
|
45
46
|
"README.md",
|
|
46
47
|
"NOTICE",
|
|
47
48
|
"LICENSE",
|
|
@@ -51,7 +52,8 @@
|
|
|
51
52
|
"ferst-check-thin": "bin/check-thin.mjs",
|
|
52
53
|
"ferst-set-cms-branch": "bin/set-cms-branch.mjs",
|
|
53
54
|
"ferst-cms-config": "bin/cms-config.mjs",
|
|
54
|
-
"ferst-update": "bin/ferst-update.mjs"
|
|
55
|
+
"ferst-update": "bin/ferst-update.mjs",
|
|
56
|
+
"ferst-modules": "bin/ferst-modules.mjs"
|
|
55
57
|
},
|
|
56
58
|
"dependencies": {
|
|
57
59
|
"zod": "^3.25.0"
|