weg-shared-layout 0.0.24 → 0.0.26
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/LICENSE +21 -21
- package/dist/cjs/weg-footer_2.cjs.entry.js +218 -193
- package/dist/collection/components/weg-footer/icons/instagram.svg +5 -5
- package/dist/collection/components/weg-footer/icons/linkedin.svg +3 -3
- package/dist/collection/components/weg-footer/icons/tiktok.svg +3 -3
- package/dist/collection/components/weg-footer/icons/youtube.svg +4 -4
- package/dist/collection/components/weg-footer/weg-footer.css +270 -218
- package/dist/collection/components/weg-footer/weg-footer.js +22 -26
- package/dist/collection/components/weg-header/weg-header.css +474 -473
- package/dist/collection/components/weg-header/weg-header.js +143 -139
- package/dist/collection/styles/shared.css +72 -72
- package/dist/collection/utils/layout.js +57 -9
- package/dist/components/p-BnMIy-A5.js +1 -0
- package/dist/components/weg-footer.js +1 -1
- package/dist/components/weg-header.js +1 -1
- package/dist/esm/weg-footer_2.entry.js +218 -193
- package/dist/types/components/weg-footer/weg-footer.d.ts +2 -2
- package/dist/types/components/weg-header/weg-header.d.ts +14 -11
- package/dist/types/components.d.ts +6 -6
- package/dist/types/types/layout-data.d.ts +13 -27
- package/dist/types/utils/layout.d.ts +9 -1
- package/dist/weg-shared-layout/p-e6eadfa1.entry.js +1 -0
- package/dist/weg-shared-layout/weg-shared-layout.esm.js +1 -1
- package/docs/angular-16-compatibility.md +235 -0
- package/docs/angular-integration-guide.md +1008 -1026
- package/docs/angular.md +232 -247
- package/docs/nextjs.md +306 -305
- package/docs/publishing.md +48 -48
- package/docs/react.md +261 -261
- package/docs/vanilla.md +138 -140
- package/package.json +5 -2
- package/readme.md +83 -108
- package/src/assets/dummy-data.json +221 -147
- package/src/constants/breakpoints.ts +7 -7
- package/dist/collection/components/weg-header/signed-in-layout.js +0 -13
- package/dist/collection/constants/weg-urls.js +0 -18
- package/dist/components/p-DbIEJ3IT.js +0 -1
- package/dist/types/components/weg-header/signed-in-layout.d.ts +0 -18
- package/dist/types/constants/weg-urls.d.ts +0 -18
- package/dist/weg-shared-layout/p-c6ec3888.entry.js +0 -1
- package/src/constants/weg-urls.ts +0 -23
- /package/dist/types/Users/{rakin/Documents/WEG/repos → tan/Documents/code}/weg-shared-layout/.stencil/test-utils/axe.d.ts +0 -0
- /package/dist/types/Users/{rakin/Documents/WEG/repos → tan/Documents/code}/weg-shared-layout/.stencil/test-utils/viewport.d.ts +0 -0
|
@@ -1,65 +1,54 @@
|
|
|
1
1
|
import { h } from "@stencil/core";
|
|
2
|
-
import {
|
|
2
|
+
import { isMenuGroup, isNonEmptyString, normalizeHeaderMenu, parseJsonProp, } from "../../utils/layout";
|
|
3
3
|
import { WEG_HOVER_CAPABLE_MEDIA_QUERY, WEG_MD_MEDIA_QUERY } from "../../constants/breakpoints";
|
|
4
4
|
import { LOGO_SRC } from "./logo-data";
|
|
5
|
-
|
|
5
|
+
const WEG_HOME = 'https://www.warwickemploymentgroup.com';
|
|
6
|
+
const ACCOUNT_HOME = 'https://account.warwickemploymentgroup.com';
|
|
7
|
+
const DEFAULT_LOGO_HREF = `${WEG_HOME}/`;
|
|
8
|
+
const ACCOUNT_LOGIN_HREF = `${ACCOUNT_HOME}/account/login`;
|
|
9
|
+
const ACCOUNT_MANAGE_HREF = `${ACCOUNT_HOME}/account/manage`;
|
|
10
|
+
const SIGNED_IN_MENU = [
|
|
11
|
+
{ label: 'Find a job', href: `${WEG_HOME}/find-a-job` },
|
|
12
|
+
{ label: 'Dashboard', href: `${ACCOUNT_HOME}/dashboard` },
|
|
13
|
+
{ label: 'Manage Account', href: `${ACCOUNT_HOME}/account/manage` },
|
|
14
|
+
{ label: 'Sign out', href: `${ACCOUNT_HOME}/account/login` },
|
|
15
|
+
];
|
|
6
16
|
const EMPTY_HEADER = {
|
|
7
|
-
|
|
8
|
-
dropdowns: [],
|
|
9
|
-
links: [],
|
|
10
|
-
signIn: null,
|
|
11
|
-
signOut: null,
|
|
17
|
+
menu: [],
|
|
12
18
|
};
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const label = item.label;
|
|
21
|
-
const items = normalizeLinks(item.items);
|
|
22
|
-
if (!isNonEmptyString(label))
|
|
23
|
-
continue;
|
|
24
|
-
if (items.length === 0)
|
|
25
|
-
continue;
|
|
26
|
-
result.push({ label: label.trim(), items });
|
|
27
|
-
}
|
|
28
|
-
return result;
|
|
19
|
+
function isSignInLink(link) {
|
|
20
|
+
const label = link.label.trim().toLowerCase();
|
|
21
|
+
if (label === 'sign out')
|
|
22
|
+
return false;
|
|
23
|
+
if (label === 'sign in')
|
|
24
|
+
return true;
|
|
25
|
+
return link.href === ACCOUNT_LOGIN_HREF;
|
|
29
26
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
return null;
|
|
33
|
-
const label = input.label;
|
|
34
|
-
const href = input.href;
|
|
35
|
-
if (!isNonEmptyString(label))
|
|
36
|
-
return null;
|
|
37
|
-
if (!isNonEmptyString(href))
|
|
38
|
-
return null;
|
|
39
|
-
return { label: label.trim(), href: href.trim() };
|
|
27
|
+
function isSignOutLink(link) {
|
|
28
|
+
return link.label.trim().toLowerCase() === 'sign out';
|
|
40
29
|
}
|
|
41
|
-
function
|
|
42
|
-
if (
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
30
|
+
function isManageAccountLink(link) {
|
|
31
|
+
if (link.label.trim().toLowerCase() === 'manage account')
|
|
32
|
+
return true;
|
|
33
|
+
return link.href === ACCOUNT_MANAGE_HREF;
|
|
34
|
+
}
|
|
35
|
+
function isFindJobLink(link) {
|
|
36
|
+
if (link.label.trim().toLowerCase() === 'find a job')
|
|
37
|
+
return true;
|
|
38
|
+
return link.href === `${WEG_HOME}/find-a-job`;
|
|
39
|
+
}
|
|
40
|
+
function isDashboardLink(link) {
|
|
41
|
+
if (link.label.trim().toLowerCase() === 'dashboard')
|
|
42
|
+
return true;
|
|
43
|
+
return link.href === `${ACCOUNT_HOME}/dashboard`;
|
|
52
44
|
}
|
|
53
45
|
function normalizeHeaderData(input) {
|
|
54
46
|
const root = (input && typeof input === 'object' ? input : {});
|
|
55
47
|
const header = root.header && typeof root.header === 'object' ? root.header : {};
|
|
56
|
-
const
|
|
48
|
+
const logoSrc = isNonEmptyString(header.logoSrc) ? header.logoSrc.trim() : undefined;
|
|
57
49
|
return {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
links: normalizeLinks(header.links),
|
|
61
|
-
signIn: normalizeSignIn(header.signIn),
|
|
62
|
-
signOut: normalizeSignOut(header.signOut),
|
|
50
|
+
logoSrc,
|
|
51
|
+
menu: normalizeHeaderMenu(header.menu),
|
|
63
52
|
};
|
|
64
53
|
}
|
|
65
54
|
function SignInIcon() {
|
|
@@ -68,6 +57,12 @@ function SignInIcon() {
|
|
|
68
57
|
function SignOutIcon() {
|
|
69
58
|
return (h("svg", { viewBox: "0 0 26 24", width: "26", height: "24", "aria-hidden": "true", focusable: "false", fill: "none" }, h("path", { d: "M19.6667 6.33333L25 11.6667L19.6667 17M25 11.6667H6.33333M14.3333 17V18.3333C14.3333 19.3942 13.9119 20.4116 13.1618 21.1618C12.4116 21.9119 11.3942 22.3333 10.3333 22.3333H5C3.93913 22.3333 2.92172 21.9119 2.17157 21.1618C1.42143 20.4116 1 19.3942 1 18.3333V5C1 3.93913 1.42143 2.92172 2.17157 2.17157C2.92172 1.42143 3.93913 1 5 1H10.3333C11.3942 1 12.4116 1.42143 13.1618 2.17157C13.9119 2.92172 14.3333 3.93913 14.3333 5V6.33333", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
70
59
|
}
|
|
60
|
+
function FindJobIcon() {
|
|
61
|
+
return (h("svg", { viewBox: "0 0 24 24", width: "20", height: "20", "aria-hidden": "true", focusable: "false", fill: "none" }, h("path", { d: "M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("rect", { x: "2", y: "6", width: "20", height: "14", rx: "2", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
62
|
+
}
|
|
63
|
+
function DashboardIcon() {
|
|
64
|
+
return (h("svg", { viewBox: "0 0 24 24", width: "20", height: "20", "aria-hidden": "true", focusable: "false", fill: "none" }, h("rect", { x: "3", y: "3", width: "7", height: "9", rx: "1", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("rect", { x: "14", y: "3", width: "7", height: "5", rx: "1", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("rect", { x: "14", y: "12", width: "7", height: "9", rx: "1", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("rect", { x: "3", y: "16", width: "7", height: "5", rx: "1", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" })));
|
|
65
|
+
}
|
|
71
66
|
function HamburgerIcon() {
|
|
72
67
|
return (h("svg", { viewBox: "0 0 24 24", width: "28", height: "28", "aria-hidden": "true", focusable: "false", fill: "none" }, h("path", { d: "M4 7h16M4 12h16M4 17h16", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" })));
|
|
73
68
|
}
|
|
@@ -77,8 +72,8 @@ function CloseIcon() {
|
|
|
77
72
|
function ToggleIcon({ expanded }) {
|
|
78
73
|
return (h("span", { class: "toggle-icon", "aria-hidden": "true" }, expanded ? (h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "none" }, h("path", { d: "M6 12h12", stroke: "currentColor", "stroke-width": "2.5", "stroke-linecap": "round" }))) : (h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "none" }, h("path", { d: "M12 6v12M6 12h12", stroke: "currentColor", "stroke-width": "2.5", "stroke-linecap": "round" })))));
|
|
79
74
|
}
|
|
80
|
-
function Logo({ href }) {
|
|
81
|
-
return (h("a", { class: "logo-link", href: href, "aria-label": "Home" }, h("img", { class: "logo", src:
|
|
75
|
+
function Logo({ href, src }) {
|
|
76
|
+
return (h("a", { class: "logo-link", href: href, "aria-label": "Home" }, h("img", { class: "logo", src: src, alt: "WEG", width: "225", height: "83" })));
|
|
82
77
|
}
|
|
83
78
|
export class WegHeader {
|
|
84
79
|
/**
|
|
@@ -88,19 +83,18 @@ export class WegHeader {
|
|
|
88
83
|
* ```json
|
|
89
84
|
* {
|
|
90
85
|
* "header": {
|
|
91
|
-
* "
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
86
|
+
* "menu": [
|
|
87
|
+
* { "label": "Find a job", "items": [{ "label": "Graduates", "href": "..." }] },
|
|
88
|
+
* { "label": "Career advice", "href": "/career-advice" },
|
|
89
|
+
* { "label": "Sign in", "href": "/account/login" }
|
|
90
|
+
* ]
|
|
96
91
|
* }
|
|
97
92
|
* }
|
|
98
93
|
* ```
|
|
99
94
|
*/
|
|
100
95
|
layout;
|
|
101
96
|
/**
|
|
102
|
-
* When true, the header
|
|
103
|
-
* Manage Account, Sign out) instead of the CMS layout.
|
|
97
|
+
* When true, the header uses the built-in signed-in menu instead of the CMS layout.
|
|
104
98
|
*/
|
|
105
99
|
signedIn = false;
|
|
106
100
|
/**
|
|
@@ -290,48 +284,55 @@ export class WegHeader {
|
|
|
290
284
|
this.menuOpen = false;
|
|
291
285
|
this.closeDropdown();
|
|
292
286
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
dropdowns: [],
|
|
299
|
-
links: [...SIGNED_IN_HEADER.links],
|
|
300
|
-
signIn: null,
|
|
301
|
-
signOut: SIGNED_IN_HEADER.signOut,
|
|
302
|
-
};
|
|
287
|
+
getActiveMenu() {
|
|
288
|
+
return this.signedIn ? SIGNED_IN_MENU : this.resolved.menu;
|
|
289
|
+
}
|
|
290
|
+
getLogoSrc() {
|
|
291
|
+
return this.resolved.logoSrc ?? LOGO_SRC;
|
|
303
292
|
}
|
|
304
293
|
getLogoHref() {
|
|
305
|
-
return
|
|
294
|
+
return DEFAULT_LOGO_HREF;
|
|
295
|
+
}
|
|
296
|
+
findSignInLink(menu) {
|
|
297
|
+
for (const item of menu) {
|
|
298
|
+
if (!isMenuGroup(item) && isSignInLink(item))
|
|
299
|
+
return item;
|
|
300
|
+
}
|
|
301
|
+
return null;
|
|
306
302
|
}
|
|
307
303
|
getManageAccountLabel() {
|
|
308
304
|
const name = this.userName?.trim();
|
|
309
305
|
return name || 'Manage Account';
|
|
310
306
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
307
|
+
renderIconNavLink(link, Icon, className, onNavigate) {
|
|
308
|
+
return (h("li", { class: "main-nav__item main-nav__item--auth", key: link.label }, h("a", { class: { 'sign-in-link': true, [className]: true }, href: link.href, onClick: () => onNavigate?.() }, h(Icon, null), link.label)));
|
|
309
|
+
}
|
|
310
|
+
renderFlatNavLink(link, onNavigate) {
|
|
311
|
+
return (h("li", { class: "main-nav__item", key: link.label }, h("a", { class: "nav-link", href: link.href, onClick: () => onNavigate?.() }, link.label)));
|
|
312
|
+
}
|
|
313
|
+
renderMenuGroup(item, onNavigate) {
|
|
314
|
+
const items = item.items ?? [];
|
|
315
|
+
const isOpen = this.openDropdown === item.label;
|
|
316
|
+
const panelId = this.getDropdownPanelId(item.label);
|
|
317
|
+
return (h("li", { class: "main-nav__item main-nav__item--dropdown", key: item.label }, h("div", { class: "nav-dropdown", onMouseEnter: () => this.handleDropdownPointerEnter(item.label), onMouseLeave: (event) => this.handleDropdownPointerLeave(event), onFocusout: (event) => this.handleDropdownFocusOut(event, item.label) }, h("button", { type: "button", class: {
|
|
318
|
+
'nav-dropdown__trigger': true,
|
|
319
|
+
'nav-dropdown__trigger--open': isOpen,
|
|
320
|
+
}, "aria-expanded": isOpen ? 'true' : 'false', "aria-haspopup": "true", "aria-controls": panelId, id: `${panelId}-trigger`, onClick: (event) => this.handleDropdownTriggerClick(event, item.label), onKeyDown: (event) => {
|
|
321
|
+
const container = event.currentTarget.closest('.nav-dropdown');
|
|
322
|
+
this.handleDropdownTriggerKeyDown(event, item.label, container);
|
|
323
|
+
} }, h("span", { class: "nav-dropdown__label" }, item.label), h(ToggleIcon, { expanded: isOpen })), isOpen ? (h("div", { class: "nav-dropdown__panel", id: panelId, role: "region", "aria-labelledby": `${panelId}-trigger`, onMouseEnter: () => this.handleDropdownPanelPointerEnter(item.label), onMouseLeave: (event) => this.handleDropdownPanelPointerLeave(event) }, h("div", { class: "nav-dropdown__accent" }, h("div", { class: "nav-dropdown__links" }, items.map((child) => (h("a", { class: "nav-dropdown__link", href: child.href, key: `${item.label}:${child.label}`, onClick: () => onNavigate?.() }, child.label))))))) : null)));
|
|
324
|
+
}
|
|
325
|
+
handleAuthClick(event, action, href, onNavigate) {
|
|
326
|
+
const emitted = this.wegAuthClick.emit({ action });
|
|
326
327
|
if (emitted.defaultPrevented) {
|
|
327
328
|
event.preventDefault();
|
|
328
329
|
onNavigate?.();
|
|
329
330
|
return;
|
|
330
331
|
}
|
|
331
|
-
if (
|
|
332
|
+
if (action === 'sign-out') {
|
|
332
333
|
event.preventDefault();
|
|
333
|
-
if (
|
|
334
|
-
window.location.assign(
|
|
334
|
+
if (href) {
|
|
335
|
+
window.location.assign(href);
|
|
335
336
|
}
|
|
336
337
|
onNavigate?.();
|
|
337
338
|
return;
|
|
@@ -339,67 +340,70 @@ export class WegHeader {
|
|
|
339
340
|
onNavigate?.();
|
|
340
341
|
}
|
|
341
342
|
renderAuthControl(options) {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
if (this.signedIn) {
|
|
363
|
-
const manageAccountLabel = this.getManageAccountLabel();
|
|
364
|
-
const signOut = SIGNED_IN_HEADER.signOut;
|
|
365
|
-
return [
|
|
366
|
-
h("li", { class: "main-nav__item main-nav__item--auth", key: "manage-account" }, h("a", { class: "sign-in-link manage-account-link", href: SIGNED_IN_HEADER.manageAccount.href, "aria-label": manageAccountLabel, onClick: () => onNavigate?.() }, h(SignInIcon, null), manageAccountLabel)),
|
|
367
|
-
h("li", { class: "main-nav__item main-nav__item--auth", key: "sign-out" }, h("a", { class: "sign-in-link sign-out-link", href: signOut.href, "aria-label": signOut.label, onClick: (event) => this.handleAuthClick(event, onNavigate) }, h(SignOutIcon, null), signOut.label)),
|
|
368
|
-
];
|
|
343
|
+
const { link, action, iconOnly, onNavigate } = options;
|
|
344
|
+
const Icon = action === 'sign-out' ? SignOutIcon : SignInIcon;
|
|
345
|
+
const classSuffix = action === 'sign-out' ? 'sign-out-link' : 'sign-in-link';
|
|
346
|
+
return (h("a", { class: {
|
|
347
|
+
[classSuffix]: !iconOnly,
|
|
348
|
+
'icon-button': !!iconOnly,
|
|
349
|
+
[options.className || '']: !!options.className,
|
|
350
|
+
}, href: link.href, "aria-label": link.label, onClick: (event) => this.handleAuthClick(event, action, link.href, onNavigate) }, h(Icon, null), !iconOnly ? link.label : null, iconOnly ? h("span", { class: "sr-only" }, link.label) : null));
|
|
351
|
+
}
|
|
352
|
+
renderManageAccountAnchor(onNavigate, iconOnly = false) {
|
|
353
|
+
const label = this.getManageAccountLabel();
|
|
354
|
+
return (h("a", { class: {
|
|
355
|
+
'sign-in-link': !iconOnly,
|
|
356
|
+
'manage-account-link': true,
|
|
357
|
+
'icon-button': iconOnly,
|
|
358
|
+
}, href: ACCOUNT_MANAGE_HREF, "aria-label": label, onClick: () => onNavigate?.() }, h(SignInIcon, null), !iconOnly ? label : null, iconOnly ? h("span", { class: "sr-only" }, label) : null));
|
|
359
|
+
}
|
|
360
|
+
renderNavItem(item, onNavigate) {
|
|
361
|
+
if (isMenuGroup(item)) {
|
|
362
|
+
return this.renderMenuGroup(item, onNavigate);
|
|
369
363
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
364
|
+
if (isSignOutLink(item)) {
|
|
365
|
+
return (h("li", { class: "main-nav__item main-nav__item--auth", key: "sign-out" }, this.renderAuthControl({ link: item, action: 'sign-out', onNavigate })));
|
|
366
|
+
}
|
|
367
|
+
if (isSignInLink(item)) {
|
|
368
|
+
return (h("li", { class: "main-nav__item main-nav__item--auth", key: "sign-in" }, this.renderAuthControl({ link: item, action: 'sign-in', onNavigate })));
|
|
369
|
+
}
|
|
370
|
+
if (isManageAccountLink(item)) {
|
|
371
|
+
return (h("li", { class: "main-nav__item main-nav__item--auth", key: "manage-account" }, this.renderManageAccountAnchor(onNavigate)));
|
|
372
|
+
}
|
|
373
|
+
if (this.signedIn && isFindJobLink(item)) {
|
|
374
|
+
return this.renderIconNavLink(item, FindJobIcon, 'find-a-job-link', onNavigate);
|
|
375
|
+
}
|
|
376
|
+
if (this.signedIn && isDashboardLink(item)) {
|
|
377
|
+
return this.renderIconNavLink(item, DashboardIcon, 'dashboard-link', onNavigate);
|
|
378
|
+
}
|
|
379
|
+
return this.renderFlatNavLink(item, onNavigate);
|
|
374
380
|
}
|
|
375
381
|
renderNav(onNavigate) {
|
|
376
|
-
|
|
377
|
-
return (h("nav", { class: "main-nav", "aria-label": "Main" }, h("ul", { class: "main-nav__list" }, dropdowns.map((dropdown) => {
|
|
378
|
-
const isOpen = this.openDropdown === dropdown.label;
|
|
379
|
-
const panelId = this.getDropdownPanelId(dropdown.label);
|
|
380
|
-
return (h("li", { class: "main-nav__item main-nav__item--dropdown", key: dropdown.label }, h("div", { class: "nav-dropdown", onMouseEnter: () => this.handleDropdownPointerEnter(dropdown.label), onMouseLeave: (event) => this.handleDropdownPointerLeave(event), onFocusout: (event) => this.handleDropdownFocusOut(event, dropdown.label) }, h("button", { type: "button", class: {
|
|
381
|
-
'nav-dropdown__trigger': true,
|
|
382
|
-
'nav-dropdown__trigger--open': isOpen,
|
|
383
|
-
}, "aria-expanded": isOpen ? 'true' : 'false', "aria-haspopup": "true", "aria-controls": panelId, id: `${panelId}-trigger`, onClick: (event) => this.handleDropdownTriggerClick(event, dropdown.label), onKeyDown: (event) => {
|
|
384
|
-
const container = event.currentTarget.closest('.nav-dropdown');
|
|
385
|
-
this.handleDropdownTriggerKeyDown(event, dropdown.label, container);
|
|
386
|
-
} }, h("span", { class: "nav-dropdown__label" }, dropdown.label), h(ToggleIcon, { expanded: isOpen })), isOpen ? (h("div", { class: "nav-dropdown__panel", id: panelId, role: "region", "aria-labelledby": `${panelId}-trigger`, onMouseEnter: () => this.handleDropdownPanelPointerEnter(dropdown.label), onMouseLeave: (event) => this.handleDropdownPanelPointerLeave(event) }, h("div", { class: "nav-dropdown__accent" }, h("div", { class: "nav-dropdown__links" }, dropdown.items.map((item) => (h("a", { class: "nav-dropdown__link", href: item.href, key: `${dropdown.label}:${item.label}`, onClick: () => onNavigate?.() }, item.label))))))) : null)));
|
|
387
|
-
}), links.map((link) => (h("li", { class: "main-nav__item", key: link.label }, h("a", { class: "nav-link", href: link.href, onClick: () => onNavigate?.() }, link.label)))), this.renderNavAuthItems(onNavigate))));
|
|
382
|
+
return (h("nav", { class: "main-nav", "aria-label": "Main" }, h("ul", { class: "main-nav__list" }, this.getActiveMenu().map((item) => this.renderNavItem(item, onNavigate)))));
|
|
388
383
|
}
|
|
389
384
|
renderCompactAuth(onNavigate) {
|
|
390
385
|
if (this.signedIn) {
|
|
391
|
-
return this.
|
|
386
|
+
return this.renderManageAccountAnchor(onNavigate, true);
|
|
392
387
|
}
|
|
393
|
-
|
|
388
|
+
const signIn = this.findSignInLink(this.resolved.menu);
|
|
389
|
+
if (!signIn?.href)
|
|
390
|
+
return null;
|
|
391
|
+
return this.renderAuthControl({
|
|
392
|
+
link: signIn,
|
|
393
|
+
action: 'sign-in',
|
|
394
|
+
iconOnly: true,
|
|
395
|
+
onNavigate,
|
|
396
|
+
});
|
|
394
397
|
}
|
|
395
398
|
render() {
|
|
396
399
|
const logoHref = this.getLogoHref();
|
|
400
|
+
const logoSrc = this.getLogoSrc();
|
|
397
401
|
const closeMenu = () => this.closeMenu();
|
|
398
402
|
const mobileMenuActive = this.isMobileMenuActive();
|
|
399
|
-
return (h("header", { key: '
|
|
403
|
+
return (h("header", { key: '6b1f9929c75b61f3afd01651a57b5923ba8b32f6', class: {
|
|
400
404
|
header: true,
|
|
401
405
|
'header--menu-open': mobileMenuActive,
|
|
402
|
-
} }, h("div", { key: '
|
|
406
|
+
} }, h("div", { key: 'a4ebb7b276d22a60fb163dfe27cfb58fef28dc52', class: "container header-inner" }, h("button", { key: '5d52fc517e5d078c209d9fd3a096bdc3a88d3bcd', type: "button", class: "menu-toggle icon-button", "aria-label": mobileMenuActive ? 'Close menu' : 'Open menu', "aria-expanded": mobileMenuActive ? 'true' : 'false', "aria-controls": "weg-header-main-nav", onClick: () => this.toggleMenu() }, mobileMenuActive ? h(CloseIcon, null) : h(HamburgerIcon, null)), h(Logo, { key: '2a94c8178c404eeac500d5014747c2df0135db1e', href: logoHref, src: logoSrc }), h("div", { key: '2d042f19d01f3bfa29735bb878189db290530429', class: "header-actions" }, this.renderCompactAuth(mobileMenuActive ? closeMenu : undefined)), h("div", { key: 'd2f001b813d443560263a09c527bba287157ad85', class: "main-nav-panel", id: "weg-header-main-nav", role: mobileMenuActive ? 'dialog' : undefined, "aria-modal": mobileMenuActive ? 'true' : undefined, "aria-label": mobileMenuActive ? 'Menu' : undefined }, this.renderNav(mobileMenuActive ? closeMenu : undefined)))));
|
|
403
407
|
}
|
|
404
408
|
static get is() { return "weg-header"; }
|
|
405
409
|
static get encapsulation() { return "shadow"; }
|
|
@@ -420,7 +424,7 @@ export class WegHeader {
|
|
|
420
424
|
"mutable": false,
|
|
421
425
|
"complexType": {
|
|
422
426
|
"original": "LayoutData | string",
|
|
423
|
-
"resolved": "string | { header?: Partial<LayoutHeaderData>; footer?: Partial<
|
|
427
|
+
"resolved": "string | { header?: Partial<LayoutHeaderData>; footer?: Partial<LayoutFooterData>; }",
|
|
424
428
|
"references": {
|
|
425
429
|
"LayoutData": {
|
|
426
430
|
"location": "import",
|
|
@@ -434,7 +438,7 @@ export class WegHeader {
|
|
|
434
438
|
"optional": true,
|
|
435
439
|
"docs": {
|
|
436
440
|
"tags": [],
|
|
437
|
-
"text": "Layout payload, supplied by the host application.\
|
|
441
|
+
"text": "Layout payload, supplied by the host application.\n\nExpected shape:\n```json\n{\n \"header\": {\n \"menu\": [\n { \"label\": \"Find a job\", \"items\": [{ \"label\": \"Graduates\", \"href\": \"...\" }] },\n { \"label\": \"Career advice\", \"href\": \"/career-advice\" },\n { \"label\": \"Sign in\", \"href\": \"/account/login\" }\n ]\n }\n}\n```"
|
|
438
442
|
},
|
|
439
443
|
"getter": false,
|
|
440
444
|
"setter": false,
|
|
@@ -453,7 +457,7 @@ export class WegHeader {
|
|
|
453
457
|
"optional": false,
|
|
454
458
|
"docs": {
|
|
455
459
|
"tags": [],
|
|
456
|
-
"text": "When true, the header
|
|
460
|
+
"text": "When true, the header uses the built-in signed-in menu instead of the CMS layout."
|
|
457
461
|
},
|
|
458
462
|
"getter": false,
|
|
459
463
|
"setter": false,
|
|
@@ -498,7 +502,7 @@ export class WegHeader {
|
|
|
498
502
|
"composed": true,
|
|
499
503
|
"docs": {
|
|
500
504
|
"tags": [],
|
|
501
|
-
"text": "Fired when the user clicks Sign in or Sign out.\
|
|
505
|
+
"text": "Fired when the user clicks Sign in or Sign out.\nCall `event.preventDefault()` in the host to handle navigation/logout yourself."
|
|
502
506
|
},
|
|
503
507
|
"complexType": {
|
|
504
508
|
"original": "{ action: LayoutHeaderAuthAction }",
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Breakpoint tokens (mobile-first min-width).
|
|
3
|
-
*
|
|
4
|
-
* - `@custom-media` names: e.g. `@media (--weg-md)` applies from 960px up.
|
|
5
|
-
* Compiled by PostCSS in stencil.config.ts.
|
|
6
|
-
* - `--weg-breakpoint-*` variables: use in property values, e.g. `max-width: var(--weg-breakpoint-md)`.
|
|
7
|
-
*
|
|
8
|
-
* Import this file in component stylesheets, or rely on shared.css which already imports it.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
:host {
|
|
12
|
-
--weg-breakpoint-sm: 640px;
|
|
13
|
-
--weg-breakpoint-md: 960px;
|
|
14
|
-
--weg-breakpoint-lg: 1280px;
|
|
15
|
-
--weg-breakpoint-xl: 1440px;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*,
|
|
20
|
-
*::before,
|
|
21
|
-
*::after {
|
|
22
|
-
box-sizing: border-box;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
:host {
|
|
26
|
-
display: block;
|
|
27
|
-
--weg-font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, 'Apple Color Emoji',
|
|
28
|
-
'Segoe UI Emoji';
|
|
29
|
-
--weg-color-accent: #948eeb;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Container widths and horizontal padding match wegcms-v2 globals.css.
|
|
34
|
-
* @see wegcms-v2/src/app/(frontend)/globals.css
|
|
35
|
-
*/
|
|
36
|
-
.container {
|
|
37
|
-
width: 100%;
|
|
38
|
-
margin-inline: auto;
|
|
39
|
-
padding-block:
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@media (width >= 960px) {
|
|
43
|
-
.container {
|
|
44
|
-
padding-inline: 1rem;
|
|
45
|
-
padding-block:
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@media (width >= 1280px) {
|
|
50
|
-
.container {
|
|
51
|
-
padding-inline: 2rem;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@media (width >= 1440px) {
|
|
57
|
-
.container {
|
|
58
|
-
padding-block:
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.sr-only {
|
|
63
|
-
position: absolute;
|
|
64
|
-
width: 1px;
|
|
65
|
-
height: 1px;
|
|
66
|
-
padding: 0;
|
|
67
|
-
margin: -1px;
|
|
68
|
-
overflow: hidden;
|
|
69
|
-
clip: rect(0, 0, 0, 0);
|
|
70
|
-
white-space: nowrap;
|
|
71
|
-
border: 0;
|
|
72
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Breakpoint tokens (mobile-first min-width).
|
|
3
|
+
*
|
|
4
|
+
* - `@custom-media` names: e.g. `@media (--weg-md)` applies from 960px up.
|
|
5
|
+
* Compiled by PostCSS in stencil.config.ts.
|
|
6
|
+
* - `--weg-breakpoint-*` variables: use in property values, e.g. `max-width: var(--weg-breakpoint-md)`.
|
|
7
|
+
*
|
|
8
|
+
* Import this file in component stylesheets, or rely on shared.css which already imports it.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
:host {
|
|
12
|
+
--weg-breakpoint-sm: 640px;
|
|
13
|
+
--weg-breakpoint-md: 960px;
|
|
14
|
+
--weg-breakpoint-lg: 1280px;
|
|
15
|
+
--weg-breakpoint-xl: 1440px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
*,
|
|
20
|
+
*::before,
|
|
21
|
+
*::after {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:host {
|
|
26
|
+
display: block;
|
|
27
|
+
--weg-font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, 'Apple Color Emoji',
|
|
28
|
+
'Segoe UI Emoji';
|
|
29
|
+
--weg-color-accent: #948eeb;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Container widths and horizontal padding match wegcms-v2 globals.css.
|
|
34
|
+
* @see wegcms-v2/src/app/(frontend)/globals.css
|
|
35
|
+
*/
|
|
36
|
+
.container {
|
|
37
|
+
width: 100%;
|
|
38
|
+
margin-inline: auto;
|
|
39
|
+
padding-block: 0.75rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@media (width >= 960px) {
|
|
43
|
+
.container {
|
|
44
|
+
padding-inline: 1rem;
|
|
45
|
+
padding-block: 1.25rem;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@media (width >= 1280px) {
|
|
50
|
+
.container {
|
|
51
|
+
padding-inline: 2rem;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@media (width >= 1440px) {
|
|
57
|
+
.container {
|
|
58
|
+
padding-block: 1.75rem;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.sr-only {
|
|
63
|
+
position: absolute;
|
|
64
|
+
width: 1px;
|
|
65
|
+
height: 1px;
|
|
66
|
+
padding: 0;
|
|
67
|
+
margin: -1px;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
clip: rect(0, 0, 0, 0);
|
|
70
|
+
white-space: nowrap;
|
|
71
|
+
border: 0;
|
|
72
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const LINK_TARGETS = new Set(['_blank', '_self', '_parent', '_top']);
|
|
1
2
|
export function parseJsonProp(value) {
|
|
2
3
|
if (typeof value !== 'string')
|
|
3
4
|
return value;
|
|
@@ -14,20 +15,67 @@ export function parseJsonProp(value) {
|
|
|
14
15
|
export function isNonEmptyString(value) {
|
|
15
16
|
return typeof value === 'string' && value.trim().length > 0;
|
|
16
17
|
}
|
|
17
|
-
export function
|
|
18
|
+
export function isMenuGroup(link) {
|
|
19
|
+
return Boolean(link.items?.length);
|
|
20
|
+
}
|
|
21
|
+
function readNestedItems(raw) {
|
|
22
|
+
return raw.items ?? raw.children;
|
|
23
|
+
}
|
|
24
|
+
function readLinkTarget(raw) {
|
|
25
|
+
const target = raw.target;
|
|
26
|
+
if (typeof target === 'string' && LINK_TARGETS.has(target)) {
|
|
27
|
+
return target;
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
export function normalizeLayoutLink(input, options) {
|
|
32
|
+
if (!input || typeof input !== 'object')
|
|
33
|
+
return null;
|
|
34
|
+
const raw = input;
|
|
35
|
+
const label = raw.label;
|
|
36
|
+
if (!isNonEmptyString(label))
|
|
37
|
+
return null;
|
|
38
|
+
const nested = readNestedItems(raw);
|
|
39
|
+
if (Array.isArray(nested)) {
|
|
40
|
+
const items = normalizeLinks(nested, { requireHref: true });
|
|
41
|
+
if (items.length > 0) {
|
|
42
|
+
return { label: label.trim(), items };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const href = raw.href;
|
|
46
|
+
if (isNonEmptyString(href)) {
|
|
47
|
+
const link = { label: label.trim(), href: href.trim() };
|
|
48
|
+
const target = readLinkTarget(raw);
|
|
49
|
+
if (target)
|
|
50
|
+
link.target = target;
|
|
51
|
+
return link;
|
|
52
|
+
}
|
|
53
|
+
return options?.requireHref === false ? null : null;
|
|
54
|
+
}
|
|
55
|
+
export function normalizeLinks(input, options) {
|
|
18
56
|
if (!Array.isArray(input))
|
|
19
57
|
return [];
|
|
58
|
+
const requireHref = options?.requireHref ?? true;
|
|
20
59
|
const result = [];
|
|
21
60
|
for (const item of input) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
61
|
+
const link = normalizeLayoutLink(item, { requireHref });
|
|
62
|
+
if (link)
|
|
63
|
+
result.push(link);
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
export function normalizeHeaderMenu(input) {
|
|
68
|
+
return normalizeLinks(input, { requireHref: false });
|
|
69
|
+
}
|
|
70
|
+
export function normalizeMenu(input) {
|
|
71
|
+
if (!Array.isArray(input))
|
|
72
|
+
return [];
|
|
73
|
+
const result = [];
|
|
74
|
+
for (const column of input) {
|
|
75
|
+
const links = normalizeLinks(column, { requireHref: true });
|
|
76
|
+
if (links.length === 0)
|
|
29
77
|
continue;
|
|
30
|
-
result.push(
|
|
78
|
+
result.push(links);
|
|
31
79
|
}
|
|
32
80
|
return result;
|
|
33
81
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n=new Set(["_blank","_self","_parent","_top"]);function t(n){if("string"!=typeof n)return n;const t=n.trim();if(t)try{return JSON.parse(t)}catch{return}}function r(n){return"string"==typeof n&&n.trim().length>0}function o(n){return Boolean(n.items?.length)}function e(t){if(!t||"object"!=typeof t)return null;const o=t,e=o.label;if(!r(e))return null;const u=function(n){return n.items??n.children}(o);if(Array.isArray(u)){const n=f(u);if(n.length>0)return{label:e.trim(),items:n}}const c=o.href;if(r(c)){const t={label:e.trim(),href:c.trim()},r=function(t){const r=t.target;if("string"==typeof r&&n.has(r))return r}(o);return r&&(t.target=r),t}return null}function f(n){if(!Array.isArray(n))return[];const t=[];for(const r of n){const n=e(r);n&&t.push(n)}return t}function u(n){return f(n)}function c(n){if(!Array.isArray(n))return[];const t=[];for(const r of n){const n=f(r);0!==n.length&&t.push(n)}return t}export{o as a,u as b,r as i,c as n,t as p}
|