@govuk-one-login/frontend-ui 5.0.0 → 5.1.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/build/all.css +1 -1
- package/build/cjs/backend/index.cjs +175 -4
- package/build/cjs/backend/index.d.cts +26 -1
- package/build/cjs/backend/index.d.ts +26 -1
- package/build/cjs/backend/index.d.ts.map +1 -1
- package/build/cjs/backend/lib/helmet.d.ts +2 -30
- package/build/cjs/backend/lib/helmet.d.ts.map +1 -1
- package/build/cjs/backend/lib/index.d.ts +1 -1
- package/build/cjs/backend/lib/index.d.ts.map +1 -1
- package/build/components/_all.scss +2 -1
- package/build/components/bases/ipv-core/ipv-core-base.njk +2 -2
- package/build/components/phase-banner/_index.scss +4 -4
- package/build/components/step-card/README.md +112 -0
- package/build/components/step-card/_index.scss +112 -0
- package/build/components/step-card/macro.njk +2 -0
- package/build/components/step-card/step-card.yaml +22 -0
- package/build/components/step-card/template.njk +33 -0
- package/build/esm/backend/index.d.ts +26 -1
- package/build/esm/backend/index.d.ts.map +1 -1
- package/build/esm/backend/index.js +170 -5
- package/build/esm/backend/lib/helmet.d.ts +2 -30
- package/build/esm/backend/lib/helmet.d.ts.map +1 -1
- package/build/esm/backend/lib/index.d.ts +1 -1
- package/build/esm/backend/lib/index.d.ts.map +1 -1
- package/package.json +11 -6
package/build/all.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@media(max-width: 640px){.govuk-header__navigation-item{border-left:none !important}.govuk-template--rebranded .govuk-header__navigation-list{padding-bottom:0px !important}.govuk-header__navigation-item{padding-top:8px !important}}.frontendUi_header_signOut-item{padding:5px 0px 5px 30px;border-left:1px solid #b1b4b6;margin-left:auto}.frontendUi_header_signOut-item--rebrand{border-left:none;padding:5px 0px 5px 0px;margin-left:auto;font-weight:700 !important}.frontendUi_header__signOut{display:flex;flex-wrap:wrap}.frontendUi-header__content{margin-left:auto}.govuk-header__navigation--signOut{padding:15px 0 15px !important}.govuk-template--rebranded .govuk-header__navigation{padding:15px 0 15px !important}@media(max-width: 640px){.govuk-header__navigation--signOut{padding:18px 0 8px !important}.govuk-template--rebranded .govuk-header__navigation{padding:18px 0 8px !important}}.govuk-template--rebranded .govuk-header__navigation-item a{font-weight:700 !important}.govuk-template--rebranded .govuk-header__navigation-item{padding-top:5px !important}@media(min-width: 20em)and (max-width: 48.0525em){.govuk-template--rebranded .govuk-header__navigation-list{padding-bottom:0px}}@media(max-width: 323px){.govuk-header__logo{padding-right:5px}.frontendUi_header_signOut-item{padding-left:0px}}@media(max-width: 261px){.frontendUi-header__content{margin-left:unset}.govuk-template--rebranded .govuk-header__navigation{padding:0px 0 8px !important}.govuk-header__logotype{max-width:100%;max-height:auto}.govuk-template--rebranded .govuk-header__logo{padding-top:5% !important;padding-bottom:5% !important}}.govuk-tag{font-size:16px;font-weight:bold;line-height:1;display:inline-block;padding-top:5px;padding-right:8px;padding-bottom:4px;padding-left:8px;outline:2px solid rgba(0,0,0,0);outline-offset:-2px;color:#fff !important;background-color:#1d70b8 !important;letter-spacing:1px !important;text-decoration:none !important;text-transform:uppercase !important}@media(max-width: 256px){.govuk-phase-banner__content{display:block}}.language-select{margin:15px 0 15px 0}.language-select__list{margin-top:1em;text-align:right}.language-select__list-item{display:inline-block}.language-select__list-item:first-child::after{content:"";display:inline-block;position:relative;top:.1875em;height:1em;border-right:.09375em solid #000}.language-select__list-item a,.language-select__list-item [aria-current]{padding:.3125em}@media screen and (max-width: 641px){.language-select__list{float:none;text-align:left;padding-bottom:10px;border-bottom:1px solid #b1b4b6}}.spinner{width:80px;height:80px;border-radius:50%;border-width:12px;border-style:solid;border-color:#dee0e2;border-top-color:#005ea5;margin-bottom:15px}@media(forced-colors: active){.spinner{forced-color-adjust:none;border-top-color:rgba(0,0,0,0) !important}}@media not (prefers-reduced-motion){.spinner{-webkit-animation:spin 2s linear infinite;animation:spin 2s linear infinite}}@media(prefers-reduced-motion){.spinner{transform:rotate(0.125turn)}}.spinner__finished{border-color:#005ea5;-webkit-animation:none;animation:none}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.centre{margin-left:auto;margin-right:auto;text-align:center;display:block}@media(max-width: 256px){.govuk-footer__crown{max-width:100%;max-height:auto}}.govuk-footer{padding-top:25px;padding-bottom:15px;border-top:1px solid #b1b4b6;color:#0b0c0c;background:#f3f2f1}.govuk-template--rebranded .govuk-footer{border-top:10px solid #1d70b8;background:#f4f8fb}.govuk-footer__copyright-logo::before{background:#6e777a}.govuk-template--rebranded .govuk-footer__copyright-logo::before{background:currentcolor}.govuk-button--progress{position:relative}.govuk-button--progress-loading{background-color:#505a5f !important;color:#fff !important;pointer-events:none !important;padding-left:40px !important}@keyframes rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.govuk-button--progress-loading::before{content:"";border:3px solid hsla(0,0%,100%,.35);border-top:3px solid #fff;border-radius:50%;width:20px;height:20px;animation:rotate 1s infinite linear;position:absolute;top:12% !important;left:8px}.govuk-progress-button--disabled{opacity:1 !important}@media(prefers-reduced-motion: reduce){.govuk-button--progress-loading{padding-left:10px !important}.govuk-button--progress-loading::before{display:none}}
|
|
1
|
+
@media(max-width: 640px){.govuk-header__navigation-item{border-left:none !important}.govuk-template--rebranded .govuk-header__navigation-list{padding-bottom:0px !important}.govuk-header__navigation-item{padding-top:8px !important}}.frontendUi_header_signOut-item{padding:5px 0px 5px 30px;border-left:1px solid #b1b4b6;margin-left:auto}.frontendUi_header_signOut-item--rebrand{border-left:none;padding:5px 0px 5px 0px;margin-left:auto;font-weight:700 !important}.frontendUi_header__signOut{display:flex;flex-wrap:wrap}.frontendUi-header__content{margin-left:auto}.govuk-header__navigation--signOut{padding:15px 0 15px !important}.govuk-template--rebranded .govuk-header__navigation{padding:15px 0 15px !important}@media(max-width: 640px){.govuk-header__navigation--signOut{padding:18px 0 8px !important}.govuk-template--rebranded .govuk-header__navigation{padding:18px 0 8px !important}}.govuk-template--rebranded .govuk-header__navigation-item a{font-weight:700 !important}.govuk-template--rebranded .govuk-header__navigation-item{padding-top:5px !important}@media(min-width: 20em)and (max-width: 48.0525em){.govuk-template--rebranded .govuk-header__navigation-list{padding-bottom:0px}}@media(max-width: 323px){.govuk-header__logo{padding-right:5px}.frontendUi_header_signOut-item{padding-left:0px}}@media(max-width: 261px){.frontendUi-header__content{margin-left:unset}.govuk-template--rebranded .govuk-header__navigation{padding:0px 0 8px !important}.govuk-header__logotype{max-width:100%;max-height:auto}.govuk-template--rebranded .govuk-header__logo{padding-top:5% !important;padding-bottom:5% !important}}.govuk-tag{font-size:16px;font-weight:bold;line-height:1;display:inline-block;padding-top:5px;padding-right:8px;padding-bottom:4px;padding-left:8px;outline:2px solid rgba(0,0,0,0);outline-offset:-2px;color:#fff !important;background-color:#1d70b8 !important;letter-spacing:1px !important;text-decoration:none !important;text-transform:uppercase !important}@media(max-width: 256px){.govuk-phase-banner__content{display:block}}.language-select{margin:15px 0 15px 0}.language-select__list{margin-top:1em;text-align:right}.language-select__list-item{display:inline-block}.language-select__list-item:first-child::after{content:"";display:inline-block;position:relative;top:.1875em;height:1em;border-right:.09375em solid #000}.language-select__list-item a,.language-select__list-item [aria-current]{padding:.3125em}@media screen and (max-width: 641px){.language-select__list{float:none;text-align:left;padding-bottom:10px;border-bottom:1px solid #b1b4b6}}.spinner{width:80px;height:80px;border-radius:50%;border-width:12px;border-style:solid;border-color:#dee0e2;border-top-color:#005ea5;margin-bottom:15px}@media(forced-colors: active){.spinner{forced-color-adjust:none;border-top-color:rgba(0,0,0,0) !important}}@media not (prefers-reduced-motion){.spinner{-webkit-animation:spin 2s linear infinite;animation:spin 2s linear infinite}}@media(prefers-reduced-motion){.spinner{transform:rotate(0.125turn)}}.spinner__finished{border-color:#005ea5;-webkit-animation:none;animation:none}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.centre{margin-left:auto;margin-right:auto;text-align:center;display:block}@media(max-width: 256px){.govuk-footer__crown{max-width:100%;max-height:auto}}.govuk-footer{padding-top:25px;padding-bottom:15px;border-top:1px solid #b1b4b6;color:#0b0c0c;background:#f3f2f1}.govuk-template--rebranded .govuk-footer{border-top:10px solid #1d70b8;background:#f4f8fb}.govuk-footer__copyright-logo::before{background:#6e777a}.govuk-template--rebranded .govuk-footer__copyright-logo::before{background:currentcolor}.govuk-button--progress{position:relative}.govuk-button--progress-loading{background-color:#505a5f !important;color:#fff !important;pointer-events:none !important;padding-left:40px !important}@keyframes rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.govuk-button--progress-loading::before{content:"";border:3px solid hsla(0,0%,100%,.35);border-top:3px solid #fff;border-radius:50%;width:20px;height:20px;animation:rotate 1s infinite linear;position:absolute;top:12% !important;left:8px}.govuk-progress-button--disabled{opacity:1 !important}@media(prefers-reduced-motion: reduce){.govuk-button--progress-loading{padding-left:10px !important}.govuk-button--progress-loading::before{display:none}}.step-card{border:1px solid #b1b4b6;gap:0;box-sizing:border-box;display:flex;flex-direction:column;align-items:flex-start;text-align:left;background:#fff;color:#0b0c0c}@media(max-width: 768px){.step-card{padding-left:.75rem;padding-right:.75rem;margin-left:.75rem;margin-right:.75rem}}@media(min-width: 769px){.step-card{padding-left:1.5rem;padding-right:1.5rem}}.step-item-container{display:flex;align-items:flex-start;border-bottom:1px solid #b1b4b6}.step-item-image{flex-shrink:0;margin-right:16px;display:flex;align-items:center;background-color:#e8f1f8;justify-content:space-around;width:70px;height:70px}.step-item-content{display:flex;align-items:flex-start;width:100%}.step-title-container{display:grid;grid-template-columns:max-content 1fr;column-gap:.25em;align-items:baseline}.step-number{grid-column:1;grid-row:1;margin-bottom:0}.step-title{grid-column:2;grid-row:1;margin-bottom:6px}.step-description{grid-column:2;grid-row:2;margin-top:0;margin-bottom:0}.step-description.govuk-list--bullet{grid-column:1/-1;padding-left:0;margin-left:1.2em;margin-top:0px}.step-card .govuk-list li:last-child .step-item-container{border-bottom:none;padding-bottom:0}@media(max-width: 300px){.step-item-container{flex-direction:column}.step-item-image{margin-right:0;margin-bottom:12px}.step-title-container{display:flex;flex-wrap:wrap;align-items:baseline}.step-description{width:100%}}.govuk-list{margin-bottom:0 !important;width:100%}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var path = require('node:path');
|
|
4
3
|
var node_fs = require('node:fs');
|
|
4
|
+
var path = require('node:path');
|
|
5
|
+
var pino = require('pino');
|
|
6
|
+
var _ = require('lodash');
|
|
5
7
|
|
|
6
8
|
var cookieBanner$1 = {
|
|
7
9
|
body1: "Rydym yn defnyddio rhai cwcis hanfodol i wneud i'r gwasanaeth hwn weithio.",
|
|
@@ -80,6 +82,9 @@ var progressButton$1 = {
|
|
|
80
82
|
longWaitingText: "Parhau i aros",
|
|
81
83
|
noJavascriptMessage: "Gall gymryd hyd at 10 eiliad i barhau i'r dudalen nesaf. Ar ôl i chi barhau, peidiwch ag ail-lwytho na chau'r dudalen hon."
|
|
82
84
|
};
|
|
85
|
+
var stepCard$1 = {
|
|
86
|
+
header: "Cwblhewch y camau canlynol"
|
|
87
|
+
};
|
|
83
88
|
var translationCy = {
|
|
84
89
|
cookieBanner: cookieBanner$1,
|
|
85
90
|
footer: footer$1,
|
|
@@ -87,7 +92,8 @@ var translationCy = {
|
|
|
87
92
|
languageSelect: languageSelect$1,
|
|
88
93
|
phaseBanner: phaseBanner$1,
|
|
89
94
|
skipLink: skipLink$1,
|
|
90
|
-
progressButton: progressButton$1
|
|
95
|
+
progressButton: progressButton$1,
|
|
96
|
+
stepCard: stepCard$1
|
|
91
97
|
};
|
|
92
98
|
|
|
93
99
|
var cookieBanner = {
|
|
@@ -167,6 +173,9 @@ var progressButton = {
|
|
|
167
173
|
longWaitingText: "Keep waiting",
|
|
168
174
|
noJavascriptMessage: "It can take up to 10 seconds to continue to the next page. After you continue, do not reload or close this page."
|
|
169
175
|
};
|
|
176
|
+
var stepCard = {
|
|
177
|
+
header: "Complete the following steps"
|
|
178
|
+
};
|
|
170
179
|
var translationEn = {
|
|
171
180
|
cookieBanner: cookieBanner,
|
|
172
181
|
footer: footer,
|
|
@@ -174,12 +183,145 @@ var translationEn = {
|
|
|
174
183
|
languageSelect: languageSelect,
|
|
175
184
|
phaseBanner: phaseBanner,
|
|
176
185
|
skipLink: skipLink,
|
|
177
|
-
progressButton: progressButton
|
|
186
|
+
progressButton: progressButton,
|
|
187
|
+
stepCard: stepCard
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
let logger;
|
|
191
|
+
const setCustomLogger = (customLogger) => {
|
|
192
|
+
logger = customLogger;
|
|
193
|
+
};
|
|
194
|
+
const getLogger = () => {
|
|
195
|
+
var _a, _b;
|
|
196
|
+
if (!logger) {
|
|
197
|
+
logger = pino.pino({
|
|
198
|
+
name: "@govuk-one-login/frontend-passthrough-headers",
|
|
199
|
+
level: (_b = (_a = process.env.LOG_LEVEL) !== null && _a !== void 0 ? _a : process.env.LOGS_LEVEL) !== null && _b !== void 0 ? _b : "warn",
|
|
200
|
+
});
|
|
201
|
+
return logger;
|
|
202
|
+
}
|
|
203
|
+
return logger;
|
|
178
204
|
};
|
|
179
205
|
|
|
206
|
+
const getGTM = (req, res, next) => {
|
|
207
|
+
res.locals.ga4ContainerId = req.app.get("APP.GTM.GA4_CONTAINER_ID");
|
|
208
|
+
res.locals.analyticsCookieDomain = req.app.get("APP.GTM.ANALYTICS_COOKIE_DOMAIN");
|
|
209
|
+
res.locals.ga4Enabled = req.app.get("APP.GTM.GA4_ENABLED");
|
|
210
|
+
res.locals.analyticsDataSensitive = req.app.get("APP.GTM.ANALYTICS_DATA_SENSITIVE");
|
|
211
|
+
res.locals.ga4PageViewEnabled = req.app.get("APP.GTM.GA4_PAGE_VIEW_ENABLED");
|
|
212
|
+
res.locals.ga4FormResponseEnabled = req.app.get("APP.GTM.GA4_FORM_RESPONSE_ENABLED");
|
|
213
|
+
res.locals.ga4FormErrorEnabled = req.app.get("APP.GTM.GA4_FORM_ERROR_ENABLED");
|
|
214
|
+
res.locals.ga4FormChangeEnabled = req.app.get("APP.GTM.GA4_FORM_CHANGE_ENABLED");
|
|
215
|
+
res.locals.ga4NavigationEnabled = req.app.get("APP.GTM.GA4_NAVIGATION_ENABLED");
|
|
216
|
+
res.locals.ga4SelectContentEnabled = req.app.get("APP.GTM.GA4_SELECT_CONTENT_ENABLED");
|
|
217
|
+
next();
|
|
218
|
+
};
|
|
219
|
+
const getAssetPath = (req, res, next) => {
|
|
220
|
+
res.locals.assetPath = req.app.get("APP.ASSET_PATH");
|
|
221
|
+
next();
|
|
222
|
+
};
|
|
223
|
+
const getLanguageToggle = (req, res, next, customLogger) => {
|
|
224
|
+
if (customLogger) {
|
|
225
|
+
setCustomLogger(customLogger);
|
|
226
|
+
}
|
|
227
|
+
const logger = getLogger();
|
|
228
|
+
const toggleValue = req.app.get("APP.LANGUAGE_TOGGLE_ENABLED");
|
|
229
|
+
res.locals.showLanguageToggle = toggleValue && toggleValue === "1";
|
|
230
|
+
res.locals.htmlLang = req.i18n.language;
|
|
231
|
+
try {
|
|
232
|
+
res.locals.currentUrl = new URL(req.protocol + "://" + req.get("host") + req.originalUrl);
|
|
233
|
+
}
|
|
234
|
+
catch (e) {
|
|
235
|
+
if (e instanceof Error) {
|
|
236
|
+
logger.warn("Error constructing url for language toggle", e.message);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
next();
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
var locals = /*#__PURE__*/Object.freeze({
|
|
243
|
+
__proto__: null,
|
|
244
|
+
getAssetPath: getAssetPath,
|
|
245
|
+
getGTM: getGTM,
|
|
246
|
+
getLanguageToggle: getLanguageToggle
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const setGTM = ({ app, ga4ContainerId, analyticsCookieDomain, ga4Enabled, ga4PageViewEnabled, ga4FormResponseEnabled, ga4FormErrorEnabled, ga4FormChangeEnabled, ga4NavigationEnabled, ga4SelectContentEnabled, analyticsDataSensitive, }) => {
|
|
250
|
+
app.set("APP.GTM.GA4_CONTAINER_ID", ga4ContainerId);
|
|
251
|
+
app.set("APP.GTM.ANALYTICS_COOKIE_DOMAIN", analyticsCookieDomain);
|
|
252
|
+
app.set("APP.GTM.GA4_ENABLED", ga4Enabled);
|
|
253
|
+
app.set("APP.GTM.GA4_PAGE_VIEW_ENABLED", ga4PageViewEnabled);
|
|
254
|
+
app.set("APP.GTM.GA4_FORM_RESPONSE_ENABLED", ga4FormResponseEnabled);
|
|
255
|
+
app.set("APP.GTM.GA4_FORM_ERROR_ENABLED", ga4FormErrorEnabled);
|
|
256
|
+
app.set("APP.GTM.GA4_FORM_CHANGE_ENABLED", ga4FormChangeEnabled);
|
|
257
|
+
app.set("APP.GTM.GA4_NAVIGATION_ENABLED", ga4NavigationEnabled);
|
|
258
|
+
app.set("APP.GTM.GA4_SELECT_CONTENT_ENABLED", ga4SelectContentEnabled);
|
|
259
|
+
app.set("APP.GTM.ANALYTICS_DATA_SENSITIVE", analyticsDataSensitive !== null && analyticsDataSensitive !== void 0 ? analyticsDataSensitive : true);
|
|
260
|
+
};
|
|
261
|
+
const setLanguageToggle = ({ app, showLanguageToggle, }) => {
|
|
262
|
+
app.set("APP.LANGUAGE_TOGGLE_ENABLED", showLanguageToggle);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
var settings = /*#__PURE__*/Object.freeze({
|
|
266
|
+
__proto__: null,
|
|
267
|
+
setGTM: setGTM,
|
|
268
|
+
setLanguageToggle: setLanguageToggle
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const baseHelmetConfig = {
|
|
272
|
+
contentSecurityPolicy: {
|
|
273
|
+
directives: {
|
|
274
|
+
defaultSrc: ["'self'"],
|
|
275
|
+
styleSrc: ["'self'"],
|
|
276
|
+
scriptSrc: [
|
|
277
|
+
"'self'",
|
|
278
|
+
(_req, res) => `'nonce-${res.locals.cspNonce}'`,
|
|
279
|
+
"'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU='",
|
|
280
|
+
"https://www.googletagmanager.com",
|
|
281
|
+
"https://www.google-analytics.com",
|
|
282
|
+
"https://ssl.google-analytics.com",
|
|
283
|
+
],
|
|
284
|
+
imgSrc: [
|
|
285
|
+
"'self'",
|
|
286
|
+
"data:",
|
|
287
|
+
"https://www.googletagmanager.com",
|
|
288
|
+
"*.google-analytics.com",
|
|
289
|
+
"*.analytics.google.com",
|
|
290
|
+
],
|
|
291
|
+
fontSrc: ["'self'"],
|
|
292
|
+
formAction: ["*"],
|
|
293
|
+
objectSrc: ["'none'"],
|
|
294
|
+
connectSrc: [
|
|
295
|
+
"'self'",
|
|
296
|
+
"*.google-analytics.com",
|
|
297
|
+
"*.analytics.google.com",
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
dnsPrefetchControl: {
|
|
302
|
+
allow: false,
|
|
303
|
+
},
|
|
304
|
+
frameguard: {
|
|
305
|
+
action: "deny",
|
|
306
|
+
},
|
|
307
|
+
hsts: {
|
|
308
|
+
maxAge: 31536000, // 1 Year
|
|
309
|
+
preload: true,
|
|
310
|
+
includeSubDomains: true,
|
|
311
|
+
},
|
|
312
|
+
referrerPolicy: false,
|
|
313
|
+
permittedCrossDomainPolicies: false,
|
|
314
|
+
expectCt: false,
|
|
315
|
+
crossOriginEmbedderPolicy: false,
|
|
316
|
+
};
|
|
317
|
+
function getHelmetConfig(additions = {}) {
|
|
318
|
+
return _.merge(baseHelmetConfig, additions);
|
|
319
|
+
}
|
|
320
|
+
|
|
180
321
|
// Implementation
|
|
181
322
|
function frontendUiMiddleware(req, res, next) {
|
|
182
323
|
res.locals.translations = req.i18n.store.data[req.i18n.language];
|
|
324
|
+
res.locals.allTranslations = req.i18n.store.data;
|
|
183
325
|
res.locals.basePath = process.cwd();
|
|
184
326
|
next();
|
|
185
327
|
}
|
|
@@ -197,6 +339,29 @@ const frontendUiMiddlewareIdentityBypass = (req, res, next) => {
|
|
|
197
339
|
res.locals.basePath = process.cwd();
|
|
198
340
|
next();
|
|
199
341
|
};
|
|
342
|
+
function resolvePath(obj, path) {
|
|
343
|
+
return path.split(".").reduce((acc, key) => (acc && typeof acc === "object" ? acc[key] : undefined), obj);
|
|
344
|
+
}
|
|
345
|
+
function buildSteps(allTranslations, currentTranslations, steps) {
|
|
346
|
+
if (!allTranslations || !steps || !currentTranslations)
|
|
347
|
+
return [];
|
|
348
|
+
return steps
|
|
349
|
+
.slice(0, 4)
|
|
350
|
+
.map(({ key, image }) => {
|
|
351
|
+
const allLanguageData = Object.keys(allTranslations).map((lng) => resolvePath(allTranslations[lng], key));
|
|
352
|
+
return {
|
|
353
|
+
data: resolvePath(currentTranslations, key),
|
|
354
|
+
allLanguageData,
|
|
355
|
+
image: image !== null && image !== void 0 ? image : null,
|
|
356
|
+
};
|
|
357
|
+
})
|
|
358
|
+
.filter(({ allLanguageData }) => allLanguageData.every((step) => { var _a, _b; return (step === null || step === void 0 ? void 0 : step.title) && ((step === null || step === void 0 ? void 0 : step.description) || ((_b = (_a = step === null || step === void 0 ? void 0 : step.bulletList) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0); }));
|
|
359
|
+
}
|
|
360
|
+
function addFrontendUiGlobals(nunjucksEnv) {
|
|
361
|
+
nunjucksEnv.addGlobal("addLanguageParam", addLanguageParam);
|
|
362
|
+
nunjucksEnv.addGlobal("contactUsUrl", contactUsUrl);
|
|
363
|
+
nunjucksEnv.addGlobal("buildSteps", buildSteps);
|
|
364
|
+
}
|
|
200
365
|
function addLanguageParam(language, url) {
|
|
201
366
|
if (!url) {
|
|
202
367
|
console.warn("URL is undefined. The parameter cannot be added, and the toggle will not work.");
|
|
@@ -211,7 +376,7 @@ function contactUsUrl(baseUrl, urlToAppend) {
|
|
|
211
376
|
}
|
|
212
377
|
try {
|
|
213
378
|
const newUrl = new URL(urlToAppend); // Create a new URL object to modify
|
|
214
|
-
newUrl.search =
|
|
379
|
+
newUrl.search = ""; // Remove the query parameters
|
|
215
380
|
const encodedUrl = encodeURIComponent(newUrl.toString()); // Encode the entire URL
|
|
216
381
|
const searchParams = new URLSearchParams({ fromURL: encodedUrl });
|
|
217
382
|
return `${baseUrl}?${searchParams.toString()}`;
|
|
@@ -248,12 +413,18 @@ const getTranslationObject = (locale, filepath) => {
|
|
|
248
413
|
return {}; // Return an empty object as a fallback
|
|
249
414
|
};
|
|
250
415
|
|
|
416
|
+
exports.addFrontendUiGlobals = addFrontendUiGlobals;
|
|
251
417
|
exports.addLanguageParam = addLanguageParam;
|
|
418
|
+
exports.buildSteps = buildSteps;
|
|
252
419
|
exports.contactUsUrl = contactUsUrl;
|
|
253
420
|
exports.frontendUiMiddleware = frontendUiMiddleware;
|
|
254
421
|
exports.frontendUiMiddlewareIdentityBypass = frontendUiMiddlewareIdentityBypass;
|
|
255
422
|
exports.frontendUiTranslationCy = translationCy;
|
|
256
423
|
exports.frontendUiTranslationEn = translationEn;
|
|
424
|
+
exports.getHelmetConfig = getHelmetConfig;
|
|
257
425
|
exports.getTranslationObject = getTranslationObject;
|
|
426
|
+
exports.locals = locals;
|
|
427
|
+
exports.resolvePath = resolvePath;
|
|
258
428
|
exports.setBaseTranslations = setBaseTranslations;
|
|
259
429
|
exports.setFrontendUiTranslations = setFrontendUiTranslations;
|
|
430
|
+
exports.settings = settings;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import i18next from "i18next";
|
|
2
1
|
import { NextFunction, Request, Response } from "express";
|
|
2
|
+
import i18next from "i18next";
|
|
3
|
+
export * from "./lib";
|
|
3
4
|
interface I18nData {
|
|
4
5
|
language: string;
|
|
5
6
|
store: {
|
|
@@ -14,6 +15,9 @@ interface ExpressRequest extends Request {
|
|
|
14
15
|
interface ExpressResponse extends Response {
|
|
15
16
|
locals: {
|
|
16
17
|
translations: unknown;
|
|
18
|
+
allTranslations: {
|
|
19
|
+
[lng: string]: unknown;
|
|
20
|
+
};
|
|
17
21
|
basePath?: string;
|
|
18
22
|
};
|
|
19
23
|
}
|
|
@@ -23,6 +27,9 @@ interface PlainRequest {
|
|
|
23
27
|
interface PlainResponse {
|
|
24
28
|
locals: {
|
|
25
29
|
translations: unknown;
|
|
30
|
+
allTranslations: {
|
|
31
|
+
[lng: string]: unknown;
|
|
32
|
+
};
|
|
26
33
|
basePath?: string;
|
|
27
34
|
};
|
|
28
35
|
}
|
|
@@ -30,6 +37,24 @@ export declare function frontendUiMiddleware(req: ExpressRequest, res: ExpressRe
|
|
|
30
37
|
export declare function frontendUiMiddleware(req: PlainRequest, res: PlainResponse, next: NextFunction): void;
|
|
31
38
|
export declare const setFrontendUiTranslations: (instanceI18n: typeof i18next) => void;
|
|
32
39
|
export declare const frontendUiMiddlewareIdentityBypass: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void;
|
|
40
|
+
export declare function resolvePath(obj: unknown, path: string): unknown;
|
|
41
|
+
type StepData = {
|
|
42
|
+
title?: unknown;
|
|
43
|
+
description?: unknown;
|
|
44
|
+
bulletList?: unknown[];
|
|
45
|
+
};
|
|
46
|
+
type StepInput = {
|
|
47
|
+
key: string;
|
|
48
|
+
image?: string | null;
|
|
49
|
+
};
|
|
50
|
+
export declare function buildSteps(allTranslations: Record<string, unknown>, currentTranslations: unknown, steps: StepInput[]): {
|
|
51
|
+
data: StepData;
|
|
52
|
+
allLanguageData: StepData[];
|
|
53
|
+
image: string | null;
|
|
54
|
+
}[];
|
|
55
|
+
export declare function addFrontendUiGlobals(nunjucksEnv: {
|
|
56
|
+
addGlobal: (name: string, value: unknown) => void;
|
|
57
|
+
}): void;
|
|
33
58
|
export declare function addLanguageParam(language: string, url?: URL): string;
|
|
34
59
|
export declare function contactUsUrl(baseUrl: string, urlToAppend: string): string | null;
|
|
35
60
|
export declare const setBaseTranslations: (instanceI18n: typeof i18next, filePath?: string) => void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import i18next from "i18next";
|
|
2
1
|
import { NextFunction, Request, Response } from "express";
|
|
2
|
+
import i18next from "i18next";
|
|
3
|
+
export * from "./lib";
|
|
3
4
|
interface I18nData {
|
|
4
5
|
language: string;
|
|
5
6
|
store: {
|
|
@@ -14,6 +15,9 @@ interface ExpressRequest extends Request {
|
|
|
14
15
|
interface ExpressResponse extends Response {
|
|
15
16
|
locals: {
|
|
16
17
|
translations: unknown;
|
|
18
|
+
allTranslations: {
|
|
19
|
+
[lng: string]: unknown;
|
|
20
|
+
};
|
|
17
21
|
basePath?: string;
|
|
18
22
|
};
|
|
19
23
|
}
|
|
@@ -23,6 +27,9 @@ interface PlainRequest {
|
|
|
23
27
|
interface PlainResponse {
|
|
24
28
|
locals: {
|
|
25
29
|
translations: unknown;
|
|
30
|
+
allTranslations: {
|
|
31
|
+
[lng: string]: unknown;
|
|
32
|
+
};
|
|
26
33
|
basePath?: string;
|
|
27
34
|
};
|
|
28
35
|
}
|
|
@@ -30,6 +37,24 @@ export declare function frontendUiMiddleware(req: ExpressRequest, res: ExpressRe
|
|
|
30
37
|
export declare function frontendUiMiddleware(req: PlainRequest, res: PlainResponse, next: NextFunction): void;
|
|
31
38
|
export declare const setFrontendUiTranslations: (instanceI18n: typeof i18next) => void;
|
|
32
39
|
export declare const frontendUiMiddlewareIdentityBypass: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void;
|
|
40
|
+
export declare function resolvePath(obj: unknown, path: string): unknown;
|
|
41
|
+
type StepData = {
|
|
42
|
+
title?: unknown;
|
|
43
|
+
description?: unknown;
|
|
44
|
+
bulletList?: unknown[];
|
|
45
|
+
};
|
|
46
|
+
type StepInput = {
|
|
47
|
+
key: string;
|
|
48
|
+
image?: string | null;
|
|
49
|
+
};
|
|
50
|
+
export declare function buildSteps(allTranslations: Record<string, unknown>, currentTranslations: unknown, steps: StepInput[]): {
|
|
51
|
+
data: StepData;
|
|
52
|
+
allLanguageData: StepData[];
|
|
53
|
+
image: string | null;
|
|
54
|
+
}[];
|
|
55
|
+
export declare function addFrontendUiGlobals(nunjucksEnv: {
|
|
56
|
+
addGlobal: (name: string, value: unknown) => void;
|
|
57
|
+
}): void;
|
|
33
58
|
export declare function addLanguageParam(language: string, url?: URL): string;
|
|
34
59
|
export declare function contactUsUrl(baseUrl: string, urlToAppend: string): string | null;
|
|
35
60
|
export declare const setBaseTranslations: (instanceI18n: typeof i18next, filePath?: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare
|
|
3
|
-
contentSecurityPolicy: {
|
|
4
|
-
directives: {
|
|
5
|
-
defaultSrc: string[];
|
|
6
|
-
styleSrc: string[];
|
|
7
|
-
scriptSrc: (string | ((_req: Request, res: Response) => string))[];
|
|
8
|
-
imgSrc: string[];
|
|
9
|
-
formAction: string[];
|
|
10
|
-
objectSrc: string[];
|
|
11
|
-
connectSrc: string[];
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
dnsPrefetchControl: {
|
|
15
|
-
allow: boolean;
|
|
16
|
-
};
|
|
17
|
-
frameguard: {
|
|
18
|
-
action: string;
|
|
19
|
-
};
|
|
20
|
-
hsts: {
|
|
21
|
-
maxAge: number;
|
|
22
|
-
preload: boolean;
|
|
23
|
-
includeSubDomains: boolean;
|
|
24
|
-
};
|
|
25
|
-
referrerPolicy: boolean;
|
|
26
|
-
permittedCrossDomainPolicies: boolean;
|
|
27
|
-
expectCt: boolean;
|
|
28
|
-
crossOriginEmbedderPolicy: boolean;
|
|
29
|
-
};
|
|
30
|
-
export default _default;
|
|
1
|
+
import { type HelmetOptions } from "helmet";
|
|
2
|
+
export declare function getHelmetConfig(additions?: HelmetOptions): HelmetOptions;
|
|
31
3
|
//# sourceMappingURL=helmet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helmet.d.ts","sourceRoot":"","sources":["../../../../src/lib/helmet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helmet.d.ts","sourceRoot":"","sources":["../../../../src/lib/helmet.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAiD5C,wBAAgB,eAAe,CAAC,SAAS,GAAE,aAAkB,GAAG,aAAa,CAE5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,UAAU,CAAC"}
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
{%- if pageErrorState %}
|
|
47
47
|
{{ 'general.govuk.errorTitlePrefix' | translate }}
|
|
48
48
|
{% endif %}
|
|
49
|
-
{%- if pageTitleKey %}{{ pageTitleKey |
|
|
49
|
+
{%- if pageTitleKey %}{{ pageTitleKey | translate(context) }} – GOV.UK One Login{% endif %}
|
|
50
50
|
{%- endblock %}
|
|
51
51
|
|
|
52
52
|
{% block bodyStart %}
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
</script>
|
|
159
159
|
{{ ga4OnPageLoad({
|
|
160
160
|
nonce: cspNonce,
|
|
161
|
-
statusCode: statusCode,
|
|
161
|
+
statusCode: statusCode,
|
|
162
162
|
dynamic: isPageDynamic,
|
|
163
163
|
englishPageTitle: pageTitleKey | translateToEnglish,
|
|
164
164
|
taxonomyLevel1: taxLevel1,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import "../../../../node_modules/govuk-frontend/govuk/helpers/_colour.scss";
|
|
1
|
+
@import "../../../../node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss";
|
|
2
2
|
// Temporarily overwrite the tag component styling to match pre-v5 appearance.
|
|
3
3
|
// This ensures a cohesive phase banner across One Login applications during the transition.
|
|
4
4
|
.govuk-tag {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
@media (max-width: 256px) {
|
|
25
|
-
.govuk-phase-banner__content{
|
|
26
|
-
|
|
27
|
-
}
|
|
25
|
+
.govuk-phase-banner__content {
|
|
26
|
+
display: block;
|
|
27
|
+
}
|
|
28
28
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Step Card
|
|
2
|
+
|
|
3
|
+
This component displays a numbered list of steps, each with an image, title, and description or bullet list. It is intended to guide users through a process in a clear, structured format.
|
|
4
|
+
|
|
5
|
+
- Renders up to 4 steps
|
|
6
|
+
- Each step's content comes from your translation files, referenced by a dot-notation key
|
|
7
|
+
- A step is only rendered if it is valid (has a `title` and either a `description` or `bulletList`) in **all** configured languages
|
|
8
|
+
- Steps that are invalid in any language are silently omitted
|
|
9
|
+
|
|
10
|
+
## How it works
|
|
11
|
+
|
|
12
|
+
Step content lives entirely in your translation files. The component uses `buildSteps` — a Nunjucks global provided by `@govuk-one-login/frontend-ui` — to resolve each step's content across all languages and filter out any steps that are incomplete in any language before passing them to the macro.
|
|
13
|
+
|
|
14
|
+
`buildSteps` is called in the outer template scope (where Nunjucks globals are available), inline within the macro call. The macro itself just renders the pre-resolved steps.
|
|
15
|
+
|
|
16
|
+
`allTranslations` and `translations` are set automatically on `res.locals` by `frontendUiMiddleware` and are available in all templates without any extra setup.
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
Register `buildSteps` as a Nunjucks global in your app's Nunjucks configuration:
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const frontendUi = require("@govuk-one-login/frontend-ui");
|
|
24
|
+
|
|
25
|
+
nunjucksEnv.addGlobal("buildSteps", frontendUi.buildSteps);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or if you are already calling `addFrontendUiGlobals`, this is included automatically:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
frontendUi.addFrontendUiGlobals(nunjucksEnv);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Ensure `frontendUiMiddleware` is registered in your Express app:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
const { frontendUiMiddleware } = require("@govuk-one-login/frontend-ui");
|
|
38
|
+
app.use(frontendUiMiddleware);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Translation file structure
|
|
42
|
+
|
|
43
|
+
Each step must have a `title` and either a `description` or a `bulletList`. The `key` you pass is the full dot-notation path from the root of the language object in your translation data.
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"pages": {
|
|
48
|
+
"myPage": {
|
|
49
|
+
"steps": [
|
|
50
|
+
{
|
|
51
|
+
"title": "Create an account",
|
|
52
|
+
"description": "Sign up using your email address."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"title": "Verify your identity",
|
|
56
|
+
"bulletList": ["Provide your passport", "Answer security questions"]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This structure must exist in **every** language's translation file. Any step missing `title` and `description`/`bulletList` in any language will be omitted from all languages.
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
```njk
|
|
69
|
+
{% from "frontend-ui/build/components/step-card/macro.njk" import frontendUiStepCard %}
|
|
70
|
+
|
|
71
|
+
{{ frontendUiStepCard({
|
|
72
|
+
translations: translations.translation.stepCard,
|
|
73
|
+
steps: buildSteps(allTranslations, translations, [
|
|
74
|
+
{ key: "translation.pages.myPage.steps.0", image: "/assets/images/step1.svg" },
|
|
75
|
+
{ key: "translation.pages.myPage.steps.1", image: "/assets/images/step2.svg" },
|
|
76
|
+
{ key: "translation.pages.myPage.steps.2", image: null }
|
|
77
|
+
])
|
|
78
|
+
}) }}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Parameters
|
|
82
|
+
|
|
83
|
+
### `frontendUiStepCard`
|
|
84
|
+
|
|
85
|
+
| Name | Type | Required | Description |
|
|
86
|
+
|------|------|----------|-------------|
|
|
87
|
+
| `translations` | object | Yes | Translations object for the component (e.g. `translations.translation.stepCard`). The template uses `translations.header` for the section heading. |
|
|
88
|
+
| `steps` | array | Yes | Array of resolved step objects returned by `buildSteps`. |
|
|
89
|
+
|
|
90
|
+
### `buildSteps(allTranslations, translations, steps)`
|
|
91
|
+
|
|
92
|
+
| Argument | Type | Description |
|
|
93
|
+
|----------|------|-------------|
|
|
94
|
+
| `allTranslations` | object | All language translation data, available in templates as `allTranslations` via `frontendUiMiddleware`. |
|
|
95
|
+
| `translations` | object | Current language translation data, available in templates as `translations` via `frontendUiMiddleware`. |
|
|
96
|
+
| `steps` | array | Array of step definitions, each with a `key` and optional `image`. |
|
|
97
|
+
|
|
98
|
+
### Step definition
|
|
99
|
+
|
|
100
|
+
| Name | Type | Required | Description |
|
|
101
|
+
|------|------|----------|-------------|
|
|
102
|
+
| `key` | string | Yes | Full dot-notation path to the step from the root of the language object (e.g. `translation.pages.myPage.steps.0`). |
|
|
103
|
+
| `image` | string | No | Path to the step image. Falls back to an inline SVG placeholder if `null` or omitted. |
|
|
104
|
+
|
|
105
|
+
## Styles
|
|
106
|
+
|
|
107
|
+
Styles for this component are defined in `_index.scss`. The component uses GOV.UK Frontend base styles and responsive breakpoints.
|
|
108
|
+
|
|
109
|
+
## Accessibility
|
|
110
|
+
|
|
111
|
+
- Step images are marked with `aria-hidden="true"` as they are decorative
|
|
112
|
+
- Steps are rendered as an ordered list (`<ol>`) to convey sequence to assistive technologies
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
@import "../../../../node_modules/govuk-frontend/dist/govuk/base.scss";
|
|
2
|
+
|
|
3
|
+
.step-card {
|
|
4
|
+
border: 1px solid $govuk-border-colour;
|
|
5
|
+
gap: 0;
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
align-items: flex-start;
|
|
10
|
+
text-align: left;
|
|
11
|
+
background: #fff;
|
|
12
|
+
color: #0b0c0c;
|
|
13
|
+
|
|
14
|
+
@media (max-width: 768px) {
|
|
15
|
+
padding-left: 0.75rem;
|
|
16
|
+
padding-right: 0.75rem;
|
|
17
|
+
margin-left: 0.75rem;
|
|
18
|
+
margin-right: 0.75rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@media (min-width: 769px) {
|
|
22
|
+
padding-left: 1.5rem;
|
|
23
|
+
padding-right: 1.5rem;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.step-item-container {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: flex-start;
|
|
30
|
+
border-bottom: 1px solid $govuk-border-colour;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.step-item-image {
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
margin-right: 16px;
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
background-color: #e8f1f8;
|
|
39
|
+
justify-content: space-around;
|
|
40
|
+
width: 70px;
|
|
41
|
+
height: 70px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.step-item-content {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: flex-start;
|
|
47
|
+
width: 100%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.step-title-container {
|
|
51
|
+
display: grid;
|
|
52
|
+
grid-template-columns: max-content 1fr;
|
|
53
|
+
column-gap: 0.25em;
|
|
54
|
+
align-items: baseline;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.step-number {
|
|
58
|
+
grid-column: 1;
|
|
59
|
+
grid-row: 1;
|
|
60
|
+
margin-bottom: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.step-title {
|
|
64
|
+
grid-column: 2;
|
|
65
|
+
grid-row: 1;
|
|
66
|
+
margin-bottom: 6px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.step-description {
|
|
70
|
+
grid-column: 2;
|
|
71
|
+
grid-row: 2;
|
|
72
|
+
margin-top: 0;
|
|
73
|
+
margin-bottom: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.step-description.govuk-list--bullet {
|
|
77
|
+
grid-column: 1 / -1;
|
|
78
|
+
padding-left: 0;
|
|
79
|
+
margin-left: 1.2em;
|
|
80
|
+
margin-top: 0px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.step-card .govuk-list li:last-child .step-item-container {
|
|
84
|
+
border-bottom: none;
|
|
85
|
+
padding-bottom: 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@media (max-width: 300px) {
|
|
89
|
+
.step-item-container {
|
|
90
|
+
flex-direction: column;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.step-item-image {
|
|
94
|
+
margin-right: 0;
|
|
95
|
+
margin-bottom: 12px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.step-title-container {
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-wrap: wrap;
|
|
101
|
+
align-items: baseline;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.step-description {
|
|
105
|
+
width: 100%;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.govuk-list {
|
|
110
|
+
margin-bottom: 0 !important;
|
|
111
|
+
width: 100%;
|
|
112
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
params:
|
|
2
|
+
- name: translations
|
|
3
|
+
type: object
|
|
4
|
+
required: true
|
|
5
|
+
description: translations object from middleware (translations.translation.stepCard)
|
|
6
|
+
- name: steps
|
|
7
|
+
type: array
|
|
8
|
+
required: true
|
|
9
|
+
description: array of step objects combining translation data and image. Maximum of 4 steps will be rendered.
|
|
10
|
+
params:
|
|
11
|
+
- name: data
|
|
12
|
+
type: object
|
|
13
|
+
required: true
|
|
14
|
+
description: the step translation object containing title, description or bulletList
|
|
15
|
+
- name: image
|
|
16
|
+
type: string
|
|
17
|
+
required: false
|
|
18
|
+
description: path to the image for this step, or null for the default placeholder
|
|
19
|
+
- name: stepsPath
|
|
20
|
+
type: string
|
|
21
|
+
required: false
|
|
22
|
+
description: dot-notation path to the steps array within each language's translation data (e.g. "translation.pages.stepCard1.steps"). Requires configureFrontendUiNunjucks to be called in your nunjucks setup. When provided, a step is only rendered if it is valid in all languages.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{% set stepCard = params.translations %}
|
|
2
|
+
{% set steps = params.steps if params.steps else [] %}
|
|
3
|
+
|
|
4
|
+
<div class="step-card govuk-!-padding-top-3 govuk-!-padding-bottom-6 govuk-!-margin-bottom-6">
|
|
5
|
+
<h2 class="govuk-heading-m">{{ stepCard.header }}</h2>
|
|
6
|
+
<ol class="govuk-list" role="list">
|
|
7
|
+
{% for step in steps %}
|
|
8
|
+
<li class="step-item" role="listitem">
|
|
9
|
+
<div class="step-item-container govuk-!-padding-top-6{% if not loop.last %} govuk-!-padding-bottom-6{% endif %}">
|
|
10
|
+
<div class="step-item-image" aria-hidden="true">
|
|
11
|
+
<img src="{{ step.image if step.image else 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2270%22 height=%2270%22 viewBox=%220 0 70 70%22%3E%3Crect width=%2270%22 height=%2270%22 fill=%22%23e8f1f8%22/%3E%3C/svg%3E' }}" alt="">
|
|
12
|
+
</div>
|
|
13
|
+
<div class="step-item-content">
|
|
14
|
+
<div class="step-title-container">
|
|
15
|
+
<span class="step-number govuk-body govuk-!-font-weight-bold">{{loop.index}}.</span>
|
|
16
|
+
<p class="govuk-body govuk-!-font-weight-bold step-title">{{step.data.title}}</p>
|
|
17
|
+
{% if step.data.description and not step.data.bulletList %}
|
|
18
|
+
<p class="govuk-body step-description">{{ step.data.description }}</p>
|
|
19
|
+
{% endif %}
|
|
20
|
+
{% if step.data.bulletList and step.data.bulletList.length %}
|
|
21
|
+
<ul class="govuk-list govuk-list--bullet step-description">
|
|
22
|
+
{% for item in step.data.bulletList %}
|
|
23
|
+
<li>{{ item }}</li>
|
|
24
|
+
{% endfor %}
|
|
25
|
+
</ul>
|
|
26
|
+
{% endif %}
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</li>
|
|
31
|
+
{% endfor %}
|
|
32
|
+
</ol>
|
|
33
|
+
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import i18next from "i18next";
|
|
2
1
|
import { NextFunction, Request, Response } from "express";
|
|
2
|
+
import i18next from "i18next";
|
|
3
|
+
export * from "./lib";
|
|
3
4
|
interface I18nData {
|
|
4
5
|
language: string;
|
|
5
6
|
store: {
|
|
@@ -14,6 +15,9 @@ interface ExpressRequest extends Request {
|
|
|
14
15
|
interface ExpressResponse extends Response {
|
|
15
16
|
locals: {
|
|
16
17
|
translations: unknown;
|
|
18
|
+
allTranslations: {
|
|
19
|
+
[lng: string]: unknown;
|
|
20
|
+
};
|
|
17
21
|
basePath?: string;
|
|
18
22
|
};
|
|
19
23
|
}
|
|
@@ -23,6 +27,9 @@ interface PlainRequest {
|
|
|
23
27
|
interface PlainResponse {
|
|
24
28
|
locals: {
|
|
25
29
|
translations: unknown;
|
|
30
|
+
allTranslations: {
|
|
31
|
+
[lng: string]: unknown;
|
|
32
|
+
};
|
|
26
33
|
basePath?: string;
|
|
27
34
|
};
|
|
28
35
|
}
|
|
@@ -30,6 +37,24 @@ export declare function frontendUiMiddleware(req: ExpressRequest, res: ExpressRe
|
|
|
30
37
|
export declare function frontendUiMiddleware(req: PlainRequest, res: PlainResponse, next: NextFunction): void;
|
|
31
38
|
export declare const setFrontendUiTranslations: (instanceI18n: typeof i18next) => void;
|
|
32
39
|
export declare const frontendUiMiddlewareIdentityBypass: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void;
|
|
40
|
+
export declare function resolvePath(obj: unknown, path: string): unknown;
|
|
41
|
+
type StepData = {
|
|
42
|
+
title?: unknown;
|
|
43
|
+
description?: unknown;
|
|
44
|
+
bulletList?: unknown[];
|
|
45
|
+
};
|
|
46
|
+
type StepInput = {
|
|
47
|
+
key: string;
|
|
48
|
+
image?: string | null;
|
|
49
|
+
};
|
|
50
|
+
export declare function buildSteps(allTranslations: Record<string, unknown>, currentTranslations: unknown, steps: StepInput[]): {
|
|
51
|
+
data: StepData;
|
|
52
|
+
allLanguageData: StepData[];
|
|
53
|
+
image: string | null;
|
|
54
|
+
}[];
|
|
55
|
+
export declare function addFrontendUiGlobals(nunjucksEnv: {
|
|
56
|
+
addGlobal: (name: string, value: unknown) => void;
|
|
57
|
+
}): void;
|
|
33
58
|
export declare function addLanguageParam(language: string, url?: URL): string;
|
|
34
59
|
export declare function contactUsUrl(baseUrl: string, urlToAppend: string): string | null;
|
|
35
60
|
export declare const setBaseTranslations: (instanceI18n: typeof i18next, filePath?: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pino } from 'pino';
|
|
4
|
+
import _ from 'lodash';
|
|
3
5
|
|
|
4
6
|
var cookieBanner$1 = {
|
|
5
7
|
body1: "Rydym yn defnyddio rhai cwcis hanfodol i wneud i'r gwasanaeth hwn weithio.",
|
|
@@ -78,6 +80,9 @@ var progressButton$1 = {
|
|
|
78
80
|
longWaitingText: "Parhau i aros",
|
|
79
81
|
noJavascriptMessage: "Gall gymryd hyd at 10 eiliad i barhau i'r dudalen nesaf. Ar ôl i chi barhau, peidiwch ag ail-lwytho na chau'r dudalen hon."
|
|
80
82
|
};
|
|
83
|
+
var stepCard$1 = {
|
|
84
|
+
header: "Cwblhewch y camau canlynol"
|
|
85
|
+
};
|
|
81
86
|
var translationCy = {
|
|
82
87
|
cookieBanner: cookieBanner$1,
|
|
83
88
|
footer: footer$1,
|
|
@@ -85,7 +90,8 @@ var translationCy = {
|
|
|
85
90
|
languageSelect: languageSelect$1,
|
|
86
91
|
phaseBanner: phaseBanner$1,
|
|
87
92
|
skipLink: skipLink$1,
|
|
88
|
-
progressButton: progressButton$1
|
|
93
|
+
progressButton: progressButton$1,
|
|
94
|
+
stepCard: stepCard$1
|
|
89
95
|
};
|
|
90
96
|
|
|
91
97
|
var cookieBanner = {
|
|
@@ -165,6 +171,9 @@ var progressButton = {
|
|
|
165
171
|
longWaitingText: "Keep waiting",
|
|
166
172
|
noJavascriptMessage: "It can take up to 10 seconds to continue to the next page. After you continue, do not reload or close this page."
|
|
167
173
|
};
|
|
174
|
+
var stepCard = {
|
|
175
|
+
header: "Complete the following steps"
|
|
176
|
+
};
|
|
168
177
|
var translationEn = {
|
|
169
178
|
cookieBanner: cookieBanner,
|
|
170
179
|
footer: footer,
|
|
@@ -172,12 +181,145 @@ var translationEn = {
|
|
|
172
181
|
languageSelect: languageSelect,
|
|
173
182
|
phaseBanner: phaseBanner,
|
|
174
183
|
skipLink: skipLink,
|
|
175
|
-
progressButton: progressButton
|
|
184
|
+
progressButton: progressButton,
|
|
185
|
+
stepCard: stepCard
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
let logger;
|
|
189
|
+
const setCustomLogger = (customLogger) => {
|
|
190
|
+
logger = customLogger;
|
|
191
|
+
};
|
|
192
|
+
const getLogger = () => {
|
|
193
|
+
var _a, _b;
|
|
194
|
+
if (!logger) {
|
|
195
|
+
logger = pino({
|
|
196
|
+
name: "@govuk-one-login/frontend-passthrough-headers",
|
|
197
|
+
level: (_b = (_a = process.env.LOG_LEVEL) !== null && _a !== void 0 ? _a : process.env.LOGS_LEVEL) !== null && _b !== void 0 ? _b : "warn",
|
|
198
|
+
});
|
|
199
|
+
return logger;
|
|
200
|
+
}
|
|
201
|
+
return logger;
|
|
176
202
|
};
|
|
177
203
|
|
|
204
|
+
const getGTM = (req, res, next) => {
|
|
205
|
+
res.locals.ga4ContainerId = req.app.get("APP.GTM.GA4_CONTAINER_ID");
|
|
206
|
+
res.locals.analyticsCookieDomain = req.app.get("APP.GTM.ANALYTICS_COOKIE_DOMAIN");
|
|
207
|
+
res.locals.ga4Enabled = req.app.get("APP.GTM.GA4_ENABLED");
|
|
208
|
+
res.locals.analyticsDataSensitive = req.app.get("APP.GTM.ANALYTICS_DATA_SENSITIVE");
|
|
209
|
+
res.locals.ga4PageViewEnabled = req.app.get("APP.GTM.GA4_PAGE_VIEW_ENABLED");
|
|
210
|
+
res.locals.ga4FormResponseEnabled = req.app.get("APP.GTM.GA4_FORM_RESPONSE_ENABLED");
|
|
211
|
+
res.locals.ga4FormErrorEnabled = req.app.get("APP.GTM.GA4_FORM_ERROR_ENABLED");
|
|
212
|
+
res.locals.ga4FormChangeEnabled = req.app.get("APP.GTM.GA4_FORM_CHANGE_ENABLED");
|
|
213
|
+
res.locals.ga4NavigationEnabled = req.app.get("APP.GTM.GA4_NAVIGATION_ENABLED");
|
|
214
|
+
res.locals.ga4SelectContentEnabled = req.app.get("APP.GTM.GA4_SELECT_CONTENT_ENABLED");
|
|
215
|
+
next();
|
|
216
|
+
};
|
|
217
|
+
const getAssetPath = (req, res, next) => {
|
|
218
|
+
res.locals.assetPath = req.app.get("APP.ASSET_PATH");
|
|
219
|
+
next();
|
|
220
|
+
};
|
|
221
|
+
const getLanguageToggle = (req, res, next, customLogger) => {
|
|
222
|
+
if (customLogger) {
|
|
223
|
+
setCustomLogger(customLogger);
|
|
224
|
+
}
|
|
225
|
+
const logger = getLogger();
|
|
226
|
+
const toggleValue = req.app.get("APP.LANGUAGE_TOGGLE_ENABLED");
|
|
227
|
+
res.locals.showLanguageToggle = toggleValue && toggleValue === "1";
|
|
228
|
+
res.locals.htmlLang = req.i18n.language;
|
|
229
|
+
try {
|
|
230
|
+
res.locals.currentUrl = new URL(req.protocol + "://" + req.get("host") + req.originalUrl);
|
|
231
|
+
}
|
|
232
|
+
catch (e) {
|
|
233
|
+
if (e instanceof Error) {
|
|
234
|
+
logger.warn("Error constructing url for language toggle", e.message);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
next();
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
var locals = /*#__PURE__*/Object.freeze({
|
|
241
|
+
__proto__: null,
|
|
242
|
+
getAssetPath: getAssetPath,
|
|
243
|
+
getGTM: getGTM,
|
|
244
|
+
getLanguageToggle: getLanguageToggle
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const setGTM = ({ app, ga4ContainerId, analyticsCookieDomain, ga4Enabled, ga4PageViewEnabled, ga4FormResponseEnabled, ga4FormErrorEnabled, ga4FormChangeEnabled, ga4NavigationEnabled, ga4SelectContentEnabled, analyticsDataSensitive, }) => {
|
|
248
|
+
app.set("APP.GTM.GA4_CONTAINER_ID", ga4ContainerId);
|
|
249
|
+
app.set("APP.GTM.ANALYTICS_COOKIE_DOMAIN", analyticsCookieDomain);
|
|
250
|
+
app.set("APP.GTM.GA4_ENABLED", ga4Enabled);
|
|
251
|
+
app.set("APP.GTM.GA4_PAGE_VIEW_ENABLED", ga4PageViewEnabled);
|
|
252
|
+
app.set("APP.GTM.GA4_FORM_RESPONSE_ENABLED", ga4FormResponseEnabled);
|
|
253
|
+
app.set("APP.GTM.GA4_FORM_ERROR_ENABLED", ga4FormErrorEnabled);
|
|
254
|
+
app.set("APP.GTM.GA4_FORM_CHANGE_ENABLED", ga4FormChangeEnabled);
|
|
255
|
+
app.set("APP.GTM.GA4_NAVIGATION_ENABLED", ga4NavigationEnabled);
|
|
256
|
+
app.set("APP.GTM.GA4_SELECT_CONTENT_ENABLED", ga4SelectContentEnabled);
|
|
257
|
+
app.set("APP.GTM.ANALYTICS_DATA_SENSITIVE", analyticsDataSensitive !== null && analyticsDataSensitive !== void 0 ? analyticsDataSensitive : true);
|
|
258
|
+
};
|
|
259
|
+
const setLanguageToggle = ({ app, showLanguageToggle, }) => {
|
|
260
|
+
app.set("APP.LANGUAGE_TOGGLE_ENABLED", showLanguageToggle);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
var settings = /*#__PURE__*/Object.freeze({
|
|
264
|
+
__proto__: null,
|
|
265
|
+
setGTM: setGTM,
|
|
266
|
+
setLanguageToggle: setLanguageToggle
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const baseHelmetConfig = {
|
|
270
|
+
contentSecurityPolicy: {
|
|
271
|
+
directives: {
|
|
272
|
+
defaultSrc: ["'self'"],
|
|
273
|
+
styleSrc: ["'self'"],
|
|
274
|
+
scriptSrc: [
|
|
275
|
+
"'self'",
|
|
276
|
+
(_req, res) => `'nonce-${res.locals.cspNonce}'`,
|
|
277
|
+
"'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU='",
|
|
278
|
+
"https://www.googletagmanager.com",
|
|
279
|
+
"https://www.google-analytics.com",
|
|
280
|
+
"https://ssl.google-analytics.com",
|
|
281
|
+
],
|
|
282
|
+
imgSrc: [
|
|
283
|
+
"'self'",
|
|
284
|
+
"data:",
|
|
285
|
+
"https://www.googletagmanager.com",
|
|
286
|
+
"*.google-analytics.com",
|
|
287
|
+
"*.analytics.google.com",
|
|
288
|
+
],
|
|
289
|
+
fontSrc: ["'self'"],
|
|
290
|
+
formAction: ["*"],
|
|
291
|
+
objectSrc: ["'none'"],
|
|
292
|
+
connectSrc: [
|
|
293
|
+
"'self'",
|
|
294
|
+
"*.google-analytics.com",
|
|
295
|
+
"*.analytics.google.com",
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
dnsPrefetchControl: {
|
|
300
|
+
allow: false,
|
|
301
|
+
},
|
|
302
|
+
frameguard: {
|
|
303
|
+
action: "deny",
|
|
304
|
+
},
|
|
305
|
+
hsts: {
|
|
306
|
+
maxAge: 31536000, // 1 Year
|
|
307
|
+
preload: true,
|
|
308
|
+
includeSubDomains: true,
|
|
309
|
+
},
|
|
310
|
+
referrerPolicy: false,
|
|
311
|
+
permittedCrossDomainPolicies: false,
|
|
312
|
+
expectCt: false,
|
|
313
|
+
crossOriginEmbedderPolicy: false,
|
|
314
|
+
};
|
|
315
|
+
function getHelmetConfig(additions = {}) {
|
|
316
|
+
return _.merge(baseHelmetConfig, additions);
|
|
317
|
+
}
|
|
318
|
+
|
|
178
319
|
// Implementation
|
|
179
320
|
function frontendUiMiddleware(req, res, next) {
|
|
180
321
|
res.locals.translations = req.i18n.store.data[req.i18n.language];
|
|
322
|
+
res.locals.allTranslations = req.i18n.store.data;
|
|
181
323
|
res.locals.basePath = process.cwd();
|
|
182
324
|
next();
|
|
183
325
|
}
|
|
@@ -195,6 +337,29 @@ const frontendUiMiddlewareIdentityBypass = (req, res, next) => {
|
|
|
195
337
|
res.locals.basePath = process.cwd();
|
|
196
338
|
next();
|
|
197
339
|
};
|
|
340
|
+
function resolvePath(obj, path) {
|
|
341
|
+
return path.split(".").reduce((acc, key) => (acc && typeof acc === "object" ? acc[key] : undefined), obj);
|
|
342
|
+
}
|
|
343
|
+
function buildSteps(allTranslations, currentTranslations, steps) {
|
|
344
|
+
if (!allTranslations || !steps || !currentTranslations)
|
|
345
|
+
return [];
|
|
346
|
+
return steps
|
|
347
|
+
.slice(0, 4)
|
|
348
|
+
.map(({ key, image }) => {
|
|
349
|
+
const allLanguageData = Object.keys(allTranslations).map((lng) => resolvePath(allTranslations[lng], key));
|
|
350
|
+
return {
|
|
351
|
+
data: resolvePath(currentTranslations, key),
|
|
352
|
+
allLanguageData,
|
|
353
|
+
image: image !== null && image !== void 0 ? image : null,
|
|
354
|
+
};
|
|
355
|
+
})
|
|
356
|
+
.filter(({ allLanguageData }) => allLanguageData.every((step) => { var _a, _b; return (step === null || step === void 0 ? void 0 : step.title) && ((step === null || step === void 0 ? void 0 : step.description) || ((_b = (_a = step === null || step === void 0 ? void 0 : step.bulletList) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0); }));
|
|
357
|
+
}
|
|
358
|
+
function addFrontendUiGlobals(nunjucksEnv) {
|
|
359
|
+
nunjucksEnv.addGlobal("addLanguageParam", addLanguageParam);
|
|
360
|
+
nunjucksEnv.addGlobal("contactUsUrl", contactUsUrl);
|
|
361
|
+
nunjucksEnv.addGlobal("buildSteps", buildSteps);
|
|
362
|
+
}
|
|
198
363
|
function addLanguageParam(language, url) {
|
|
199
364
|
if (!url) {
|
|
200
365
|
console.warn("URL is undefined. The parameter cannot be added, and the toggle will not work.");
|
|
@@ -209,7 +374,7 @@ function contactUsUrl(baseUrl, urlToAppend) {
|
|
|
209
374
|
}
|
|
210
375
|
try {
|
|
211
376
|
const newUrl = new URL(urlToAppend); // Create a new URL object to modify
|
|
212
|
-
newUrl.search =
|
|
377
|
+
newUrl.search = ""; // Remove the query parameters
|
|
213
378
|
const encodedUrl = encodeURIComponent(newUrl.toString()); // Encode the entire URL
|
|
214
379
|
const searchParams = new URLSearchParams({ fromURL: encodedUrl });
|
|
215
380
|
return `${baseUrl}?${searchParams.toString()}`;
|
|
@@ -246,4 +411,4 @@ const getTranslationObject = (locale, filepath) => {
|
|
|
246
411
|
return {}; // Return an empty object as a fallback
|
|
247
412
|
};
|
|
248
413
|
|
|
249
|
-
export { addLanguageParam, contactUsUrl, frontendUiMiddleware, frontendUiMiddlewareIdentityBypass, translationCy as frontendUiTranslationCy, translationEn as frontendUiTranslationEn, getTranslationObject, setBaseTranslations, setFrontendUiTranslations };
|
|
414
|
+
export { addFrontendUiGlobals, addLanguageParam, buildSteps, contactUsUrl, frontendUiMiddleware, frontendUiMiddlewareIdentityBypass, translationCy as frontendUiTranslationCy, translationEn as frontendUiTranslationEn, getHelmetConfig, getTranslationObject, locals, resolvePath, setBaseTranslations, setFrontendUiTranslations, settings };
|
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare
|
|
3
|
-
contentSecurityPolicy: {
|
|
4
|
-
directives: {
|
|
5
|
-
defaultSrc: string[];
|
|
6
|
-
styleSrc: string[];
|
|
7
|
-
scriptSrc: (string | ((_req: Request, res: Response) => string))[];
|
|
8
|
-
imgSrc: string[];
|
|
9
|
-
formAction: string[];
|
|
10
|
-
objectSrc: string[];
|
|
11
|
-
connectSrc: string[];
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
dnsPrefetchControl: {
|
|
15
|
-
allow: boolean;
|
|
16
|
-
};
|
|
17
|
-
frameguard: {
|
|
18
|
-
action: string;
|
|
19
|
-
};
|
|
20
|
-
hsts: {
|
|
21
|
-
maxAge: number;
|
|
22
|
-
preload: boolean;
|
|
23
|
-
includeSubDomains: boolean;
|
|
24
|
-
};
|
|
25
|
-
referrerPolicy: boolean;
|
|
26
|
-
permittedCrossDomainPolicies: boolean;
|
|
27
|
-
expectCt: boolean;
|
|
28
|
-
crossOriginEmbedderPolicy: boolean;
|
|
29
|
-
};
|
|
30
|
-
export default _default;
|
|
1
|
+
import { type HelmetOptions } from "helmet";
|
|
2
|
+
export declare function getHelmetConfig(additions?: HelmetOptions): HelmetOptions;
|
|
31
3
|
//# sourceMappingURL=helmet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helmet.d.ts","sourceRoot":"","sources":["../../../../src/lib/helmet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helmet.d.ts","sourceRoot":"","sources":["../../../../src/lib/helmet.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAiD5C,wBAAgB,eAAe,CAAC,SAAS,GAAE,aAAkB,GAAG,aAAa,CAE5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,UAAU,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@govuk-one-login/frontend-ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/cjs/backend/index.cjs",
|
|
6
6
|
"module": "build/esm/backend/index.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"build": "rollup -c",
|
|
13
13
|
"dev": "rollup -c --watch",
|
|
14
14
|
"test": "jest --coverage src",
|
|
15
|
-
"test:visual": "
|
|
16
|
-
"test:visual:update": "
|
|
15
|
+
"test:visual": "playwright test browser-tests/functional-tests",
|
|
16
|
+
"test:visual:update": "playwright test browser-tests/functional-tests --update-snapshots"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"build/",
|
|
@@ -43,7 +43,13 @@
|
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@govuk-one-login/frontend-analytics": " ^3.0.1 || ^4.0.3",
|
|
45
45
|
"express": "^5.1.0 || >= 4.21.2",
|
|
46
|
-
"govuk-frontend": "^4.10.1 || ^5.0.0"
|
|
46
|
+
"govuk-frontend": "^4.10.1 || ^5.0.0",
|
|
47
|
+
"hmpo-components": "^7.1.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"hmpo-components": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
47
53
|
},
|
|
48
54
|
"exports": {
|
|
49
55
|
".": {
|
|
@@ -57,7 +63,6 @@
|
|
|
57
63
|
},
|
|
58
64
|
"types": "./build/esm/backend/index.d.ts",
|
|
59
65
|
"optionalDependencies": {
|
|
60
|
-
"@govuk-one-login/frontend-analytics": "^4.0.7"
|
|
61
|
-
"hmpo-components": "^7.1.0"
|
|
66
|
+
"@govuk-one-login/frontend-analytics": "^4.0.7"
|
|
62
67
|
}
|
|
63
68
|
}
|