weg-shared-layout 0.0.49 → 0.0.50
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/dist/cjs/weg-footer_2.cjs.entry.js +1 -1
- package/dist/collection/components/weg-footer/weg-footer.css +4 -0
- package/dist/components/weg-footer.js +1 -1
- package/dist/esm/weg-footer_2.entry.js +1 -1
- package/dist/weg-shared-layout/p-21d4edfc.entry.js +1 -0
- package/dist/weg-shared-layout/weg-shared-layout.esm.js +1 -1
- package/docs/README.md +54 -54
- package/docs/angular.md +440 -440
- package/docs/nextjs.md +313 -313
- package/docs/publishing.md +65 -65
- package/docs/react.md +291 -291
- package/docs/vanilla.md +159 -159
- package/package.json +1 -1
- package/readme.md +121 -121
- package/src/types/menus-data.ts +44 -44
- package/src/utils/menus.ts +65 -65
- package/dist/weg-shared-layout/p-6737bde4.entry.js +0 -1
package/docs/vanilla.md
CHANGED
|
@@ -1,159 +1,159 @@
|
|
|
1
|
-
# Plain HTML / vanilla JS
|
|
2
|
-
|
|
3
|
-
## What you get
|
|
4
|
-
|
|
5
|
-
| Tag | Purpose |
|
|
6
|
-
| --- | --- |
|
|
7
|
-
| `<weg-header>` | Site header — bundled logo, CMS nav (signed out), built-in nav (signed in), Sign in / Manage Account / Sign out |
|
|
8
|
-
| `<weg-footer>` | Site footer — social links, menu, credits, copyright |
|
|
9
|
-
|
|
10
|
-
Both components are **presentational**: they do **not** fetch data. Pass the same `layout` payload to each.
|
|
11
|
-
|
|
12
|
-
WEG21 API schema: [`weg21-bootstrap.json`](../src/assets/weg21-bootstrap.json), [`weg21-menus.json`](../src/assets/weg21-menus.json)
|
|
13
|
-
|
|
14
|
-
## Install & register
|
|
15
|
-
|
|
16
|
-
With a bundler that resolves `node_modules` and package **`exports`** (TypeScript: `resolveJsonModule` + `moduleResolution` `bundler` or `node16` — see [angular.md](./angular.md)):
|
|
17
|
-
|
|
18
|
-
```html
|
|
19
|
-
<weg-header id="header"></weg-header>
|
|
20
|
-
<main><!-- your content --></main>
|
|
21
|
-
<weg-footer id="footer"></weg-footer>
|
|
22
|
-
|
|
23
|
-
<script type="module">
|
|
24
|
-
import { defineCustomElements } from 'weg-shared-layout/loader';
|
|
25
|
-
import { dummyWeg21LayoutData } from 'weg-shared-layout/menus';
|
|
26
|
-
const layout = dummyWeg21LayoutData();
|
|
27
|
-
|
|
28
|
-
defineCustomElements();
|
|
29
|
-
|
|
30
|
-
const header = document.getElementById('header');
|
|
31
|
-
const footer = document.getElementById('footer');
|
|
32
|
-
|
|
33
|
-
header.layout = layout;
|
|
34
|
-
footer.layout = layout;
|
|
35
|
-
|
|
36
|
-
function updateCurrentPath() {
|
|
37
|
-
const { pathname, search } = window.location;
|
|
38
|
-
header.currentPath = search ? `${pathname}${search}` : pathname;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
updateCurrentPath();
|
|
42
|
-
window.addEventListener('popstate', updateCurrentPath);
|
|
43
|
-
</script>
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Side-effect imports (no loader) if you only need specific tags:
|
|
47
|
-
|
|
48
|
-
```js
|
|
49
|
-
import 'weg-shared-layout/weg-header';
|
|
50
|
-
import 'weg-shared-layout/weg-footer';
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## `layout` property vs attribute
|
|
54
|
-
|
|
55
|
-
Assign the **`layout` JavaScript property** (recommended):
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
element.layout = layoutObject;
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Or pass a JSON **string** on the `layout` attribute:
|
|
62
|
-
|
|
63
|
-
```html
|
|
64
|
-
<weg-header layout='{"header":{"menu":[]}}'></weg-header>
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Header layout fields (signed out)
|
|
68
|
-
|
|
69
|
-
| Field | Purpose |
|
|
70
|
-
| --- | --- |
|
|
71
|
-
| `header.logoSrc` | Logo image URL (bundled if omitted) |
|
|
72
|
-
| `header.logoHref` | Logo link URL (WEG homepage if omitted) |
|
|
73
|
-
| `header.menu` | Unified nav — groups with `items[]`, flat links with `href` (incl. Sign in) |
|
|
74
|
-
|
|
75
|
-
See [`weg21-menus.json`](../src/assets/weg21-menus.json) for absolute URL examples in menu links.
|
|
76
|
-
|
|
77
|
-
## Header auth (Sign in / Sign out)
|
|
78
|
-
|
|
79
|
-
### Signed out
|
|
80
|
-
|
|
81
|
-
Renders `header.menu` from `layout`. Add sign-in as a normal link — `{ "label": "Sign in", "href": "…" }` — like Register. The header recognizes it by label or login URL and follows `href` on click.
|
|
82
|
-
|
|
83
|
-
### Signed in
|
|
84
|
-
|
|
85
|
-
Set **`signedIn`** and optionally **`userName`**. CMS nav is ignored; built-in links are shown (Find a job, Dashboard, Manage Account, Sign out). Set **`accountBaseUrl`** when account links should use a non-production portal.
|
|
86
|
-
|
|
87
|
-
```js
|
|
88
|
-
header.signedIn = true;
|
|
89
|
-
header.userName = 'Alex';
|
|
90
|
-
// header.accountBaseUrl = 'https://account-staging.example.com';
|
|
91
|
-
// or
|
|
92
|
-
header.setAttribute('signed-in', '');
|
|
93
|
-
header.setAttribute('user-name', 'Alex');
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Listen for **`wegAuthClick`** to handle sign-out (call your logout API, then redirect):
|
|
97
|
-
|
|
98
|
-
```js
|
|
99
|
-
header.addEventListener('wegAuthClick', async (event) => {
|
|
100
|
-
if (event.detail.action !== 'sign-out') return;
|
|
101
|
-
|
|
102
|
-
event.preventDefault();
|
|
103
|
-
header.signedIn = false;
|
|
104
|
-
await logout();
|
|
105
|
-
window.location.assign('/');
|
|
106
|
-
});
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
| `event.detail.action` | Default behaviour if not prevented |
|
|
110
|
-
| --- | --- |
|
|
111
|
-
| `'sign-in'` | Browser follows the link's `href` |
|
|
112
|
-
| `'sign-out'` | Emits event only — no navigation (host handles logout) |
|
|
113
|
-
|
|
114
|
-
## Nav active state
|
|
115
|
-
|
|
116
|
-
Set **`currentPath`** (property) or **`current-path`** (attribute) to the current pathname. Include `?query` when dropdown links use search params.
|
|
117
|
-
|
|
118
|
-
```js
|
|
119
|
-
function syncCurrentPath() {
|
|
120
|
-
const { pathname, search } = window.location;
|
|
121
|
-
header.currentPath = search ? `${pathname}${search}` : pathname;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
syncCurrentPath();
|
|
125
|
-
window.addEventListener('popstate', syncCurrentPath);
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
| Link type | Match rule |
|
|
129
|
-
| --- | --- |
|
|
130
|
-
| Flat nav link | Prefix match on pathname |
|
|
131
|
-
| Dropdown child | Exact pathname (+ query when href has `?`) |
|
|
132
|
-
| Dropdown parent | Active when any child matches |
|
|
133
|
-
| Sign in / Sign out | Never highlighted |
|
|
134
|
-
|
|
135
|
-
Active links use **`weg-purple-200`** (`#CDCFF8`).
|
|
136
|
-
|
|
137
|
-
Logo **image** uses `header.logoSrc` (bundled if omitted). Logo **link** uses `header.logoHref` when provided; otherwise it goes to the WEG homepage.
|
|
138
|
-
|
|
139
|
-
## Without a bundler
|
|
140
|
-
|
|
141
|
-
Fetch `weg21-bootstrap.json` and `weg21-menus.json`, map with the same logic as [`menusToLayoutData`](../src/utils/menus.ts), then assign properties:
|
|
142
|
-
|
|
143
|
-
```js
|
|
144
|
-
const [bootstrapRes, menusRes] = await Promise.all([
|
|
145
|
-
fetch('/assets/weg21-bootstrap.json'),
|
|
146
|
-
fetch('/assets/weg21-menus.json'),
|
|
147
|
-
]);
|
|
148
|
-
const layout = await res.json();
|
|
149
|
-
document.getElementById('header').layout = layout;
|
|
150
|
-
document.getElementById('footer').layout = layout;
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## See also
|
|
154
|
-
|
|
155
|
-
- **[Documentation index](./README.md)**
|
|
156
|
-
- **[React SPA](./react.md)**
|
|
157
|
-
- **[Next.js App Router](./nextjs.md)**
|
|
158
|
-
- **[Angular](./angular.md)** · **[Angular 16 demo](../demo/angular16/README.md)**
|
|
159
|
-
- **[Package readme](../readme.md)**
|
|
1
|
+
# Plain HTML / vanilla JS
|
|
2
|
+
|
|
3
|
+
## What you get
|
|
4
|
+
|
|
5
|
+
| Tag | Purpose |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `<weg-header>` | Site header — bundled logo, CMS nav (signed out), built-in nav (signed in), Sign in / Manage Account / Sign out |
|
|
8
|
+
| `<weg-footer>` | Site footer — social links, menu, credits, copyright |
|
|
9
|
+
|
|
10
|
+
Both components are **presentational**: they do **not** fetch data. Pass the same `layout` payload to each.
|
|
11
|
+
|
|
12
|
+
WEG21 API schema: [`weg21-bootstrap.json`](../src/assets/weg21-bootstrap.json), [`weg21-menus.json`](../src/assets/weg21-menus.json)
|
|
13
|
+
|
|
14
|
+
## Install & register
|
|
15
|
+
|
|
16
|
+
With a bundler that resolves `node_modules` and package **`exports`** (TypeScript: `resolveJsonModule` + `moduleResolution` `bundler` or `node16` — see [angular.md](./angular.md)):
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<weg-header id="header"></weg-header>
|
|
20
|
+
<main><!-- your content --></main>
|
|
21
|
+
<weg-footer id="footer"></weg-footer>
|
|
22
|
+
|
|
23
|
+
<script type="module">
|
|
24
|
+
import { defineCustomElements } from 'weg-shared-layout/loader';
|
|
25
|
+
import { dummyWeg21LayoutData } from 'weg-shared-layout/menus';
|
|
26
|
+
const layout = dummyWeg21LayoutData();
|
|
27
|
+
|
|
28
|
+
defineCustomElements();
|
|
29
|
+
|
|
30
|
+
const header = document.getElementById('header');
|
|
31
|
+
const footer = document.getElementById('footer');
|
|
32
|
+
|
|
33
|
+
header.layout = layout;
|
|
34
|
+
footer.layout = layout;
|
|
35
|
+
|
|
36
|
+
function updateCurrentPath() {
|
|
37
|
+
const { pathname, search } = window.location;
|
|
38
|
+
header.currentPath = search ? `${pathname}${search}` : pathname;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
updateCurrentPath();
|
|
42
|
+
window.addEventListener('popstate', updateCurrentPath);
|
|
43
|
+
</script>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Side-effect imports (no loader) if you only need specific tags:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import 'weg-shared-layout/weg-header';
|
|
50
|
+
import 'weg-shared-layout/weg-footer';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## `layout` property vs attribute
|
|
54
|
+
|
|
55
|
+
Assign the **`layout` JavaScript property** (recommended):
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
element.layout = layoutObject;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or pass a JSON **string** on the `layout` attribute:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<weg-header layout='{"header":{"menu":[]}}'></weg-header>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Header layout fields (signed out)
|
|
68
|
+
|
|
69
|
+
| Field | Purpose |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `header.logoSrc` | Logo image URL (bundled if omitted) |
|
|
72
|
+
| `header.logoHref` | Logo link URL (WEG homepage if omitted) |
|
|
73
|
+
| `header.menu` | Unified nav — groups with `items[]`, flat links with `href` (incl. Sign in) |
|
|
74
|
+
|
|
75
|
+
See [`weg21-menus.json`](../src/assets/weg21-menus.json) for absolute URL examples in menu links.
|
|
76
|
+
|
|
77
|
+
## Header auth (Sign in / Sign out)
|
|
78
|
+
|
|
79
|
+
### Signed out
|
|
80
|
+
|
|
81
|
+
Renders `header.menu` from `layout`. Add sign-in as a normal link — `{ "label": "Sign in", "href": "…" }` — like Register. The header recognizes it by label or login URL and follows `href` on click.
|
|
82
|
+
|
|
83
|
+
### Signed in
|
|
84
|
+
|
|
85
|
+
Set **`signedIn`** and optionally **`userName`**. CMS nav is ignored; built-in links are shown (Find a job, Dashboard, Manage Account, Sign out). Set **`accountBaseUrl`** when account links should use a non-production portal.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
header.signedIn = true;
|
|
89
|
+
header.userName = 'Alex';
|
|
90
|
+
// header.accountBaseUrl = 'https://account-staging.example.com';
|
|
91
|
+
// or
|
|
92
|
+
header.setAttribute('signed-in', '');
|
|
93
|
+
header.setAttribute('user-name', 'Alex');
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Listen for **`wegAuthClick`** to handle sign-out (call your logout API, then redirect):
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
header.addEventListener('wegAuthClick', async (event) => {
|
|
100
|
+
if (event.detail.action !== 'sign-out') return;
|
|
101
|
+
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
header.signedIn = false;
|
|
104
|
+
await logout();
|
|
105
|
+
window.location.assign('/');
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
| `event.detail.action` | Default behaviour if not prevented |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| `'sign-in'` | Browser follows the link's `href` |
|
|
112
|
+
| `'sign-out'` | Emits event only — no navigation (host handles logout) |
|
|
113
|
+
|
|
114
|
+
## Nav active state
|
|
115
|
+
|
|
116
|
+
Set **`currentPath`** (property) or **`current-path`** (attribute) to the current pathname. Include `?query` when dropdown links use search params.
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
function syncCurrentPath() {
|
|
120
|
+
const { pathname, search } = window.location;
|
|
121
|
+
header.currentPath = search ? `${pathname}${search}` : pathname;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
syncCurrentPath();
|
|
125
|
+
window.addEventListener('popstate', syncCurrentPath);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
| Link type | Match rule |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| Flat nav link | Prefix match on pathname |
|
|
131
|
+
| Dropdown child | Exact pathname (+ query when href has `?`) |
|
|
132
|
+
| Dropdown parent | Active when any child matches |
|
|
133
|
+
| Sign in / Sign out | Never highlighted |
|
|
134
|
+
|
|
135
|
+
Active links use **`weg-purple-200`** (`#CDCFF8`).
|
|
136
|
+
|
|
137
|
+
Logo **image** uses `header.logoSrc` (bundled if omitted). Logo **link** uses `header.logoHref` when provided; otherwise it goes to the WEG homepage.
|
|
138
|
+
|
|
139
|
+
## Without a bundler
|
|
140
|
+
|
|
141
|
+
Fetch `weg21-bootstrap.json` and `weg21-menus.json`, map with the same logic as [`menusToLayoutData`](../src/utils/menus.ts), then assign properties:
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
const [bootstrapRes, menusRes] = await Promise.all([
|
|
145
|
+
fetch('/assets/weg21-bootstrap.json'),
|
|
146
|
+
fetch('/assets/weg21-menus.json'),
|
|
147
|
+
]);
|
|
148
|
+
const layout = await res.json();
|
|
149
|
+
document.getElementById('header').layout = layout;
|
|
150
|
+
document.getElementById('footer').layout = layout;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## See also
|
|
154
|
+
|
|
155
|
+
- **[Documentation index](./README.md)**
|
|
156
|
+
- **[React SPA](./react.md)**
|
|
157
|
+
- **[Next.js App Router](./nextjs.md)**
|
|
158
|
+
- **[Angular](./angular.md)** · **[Angular 16 demo](../demo/angular16/README.md)**
|
|
159
|
+
- **[Package readme](../readme.md)**
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
# weg-shared-layout
|
|
2
|
-
|
|
3
|
-
> Shared layout Web Components.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm i weg-shared-layout
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## How it works
|
|
12
|
-
|
|
13
|
-
`<weg-header>` and `<weg-footer>` are **presentational** Web Components: they do **not** fetch data.
|
|
14
|
-
|
|
15
|
-
Load layout from the **WEG CMS WEG21 API**, then pass the mapped object to `layout` on each tag:
|
|
16
|
-
|
|
17
|
-
| Endpoint | Purpose |
|
|
18
|
-
| --- | --- |
|
|
19
|
-
| `GET https://warwickemploymentgroup.com/api/v1/weg21` | Logo URLs, footer social + legal copy |
|
|
20
|
-
| `GET …/api/v1/weg21/menus` | Header (`ext` / `int`) and footer link columns |
|
|
21
|
-
|
|
22
|
-
Both require the `wcms-api-key` header. Use `fetchWeg21Layout` from `weg-shared-layout/menus`:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
import { fetchWeg21Layout } from 'weg-shared-layout/menus';
|
|
26
|
-
|
|
27
|
-
const layout = await fetchWeg21Layout({
|
|
28
|
-
apiKey: process.env.WCMS_API_KEY,
|
|
29
|
-
});
|
|
30
|
-
// layout.header.menu, layout.footer.menu, layout.footer.social, …
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
[`weg21-bootstrap.json`](src/assets/weg21-bootstrap.json) and [`weg21-menus.json`](src/assets/weg21-menus.json) mirror the **WEG21 API response schemas** (`GET /api/v1/weg21` and `/menus`). Map to `layout` with `dummyWeg21LayoutData()` or `menusToLayoutData`.
|
|
34
|
-
|
|
35
|
-
### Layout shape (abbreviated)
|
|
36
|
-
|
|
37
|
-
```json
|
|
38
|
-
{
|
|
39
|
-
"header": {
|
|
40
|
-
"menu": [
|
|
41
|
-
{ "label": "Find a job", "items": [{ "label": "Graduates", "href": "…" }] },
|
|
42
|
-
{ "label": "Sign in", "href": "…" }
|
|
43
|
-
]
|
|
44
|
-
},
|
|
45
|
-
"footer": {
|
|
46
|
-
"menu": [[{ "label": "About WEG", "href": "…" }]],
|
|
47
|
-
"social": [{ "platform": "LinkedIn", "href": "…" }],
|
|
48
|
-
"credits": "…",
|
|
49
|
-
"copyright": "…"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
| Field | Used when | Notes |
|
|
55
|
-
| --- | --- | --- |
|
|
56
|
-
| `header.logoSrc` | Signed out | Optional CMS logo URL; bundled PNG if omitted |
|
|
57
|
-
| `header.logoHref` | Always | Optional logo link URL; WEG homepage if omitted |
|
|
58
|
-
| `header.menu` | Signed out | Groups use `items`; flat links use `href` |
|
|
59
|
-
| `footer.menu` | Always | `LayoutLink[][]` — one column per inner array |
|
|
60
|
-
| `footer.social` | Always | LinkedIn, Instagram, TikTok, or YouTube |
|
|
61
|
-
| `footer.credits` / `footer.copyright` | Always | Legal copy |
|
|
62
|
-
|
|
63
|
-
### Auth (Sign in / Sign out)
|
|
64
|
-
|
|
65
|
-
**Signed out**: renders `header.menu`. Sign-in is a normal link — add `{ "label": "Sign in", "href": "…" }` like Register or Career advice. The header recognizes it by label or login URL and follows `href` on click.
|
|
66
|
-
|
|
67
|
-
**Signed in** (`signed-in` true): ignores CMS `header.menu` and shows built-in Find a job, Dashboard, Manage Account, and Sign out.
|
|
68
|
-
|
|
69
|
-
Set **`signed-in`** from your app session state. Pass **`user-name`** for Manage Account. Pass **`account-base-url`** when account links should point at a non-production portal. Pass **`current-path`** (e.g. `/career-advice/my-article`) to highlight the active nav item. **Sign out** emits **`wegAuthClick`** — the host must call `event.preventDefault()` and run your logout flow (API call, clear session, redirect).
|
|
70
|
-
|
|
71
|
-
### Nav active state
|
|
72
|
-
|
|
73
|
-
| Link type | Match rule |
|
|
74
|
-
| --- | --- |
|
|
75
|
-
| Flat nav link | Prefix — `/career-advice` matches `/career-advice/foo` |
|
|
76
|
-
| Dropdown child | Exact pathname (+ query when href includes `?`) |
|
|
77
|
-
| Dropdown parent | Active background when any child matches |
|
|
78
|
-
| Sign in / Sign out | Never highlighted |
|
|
79
|
-
|
|
80
|
-
Active links use **`weg-purple-200`** (`#CDCFF8`). Omit `current-path` to disable active styling.
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
header.addEventListener('wegAuthClick', async (event) => {
|
|
84
|
-
if (event.detail.action !== 'sign-out') return;
|
|
85
|
-
event.preventDefault();
|
|
86
|
-
await logout();
|
|
87
|
-
window.location.assign('/');
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Package imports (TypeScript / bundlers)
|
|
92
|
-
|
|
93
|
-
| Subpath | Use |
|
|
94
|
-
| --- | --- |
|
|
95
|
-
| `weg-shared-layout/loader` | `defineCustomElements()` — **recommended** |
|
|
96
|
-
| `weg-shared-layout/menus` | `fetchWeg21Layout`, `menusToLayoutData` |
|
|
97
|
-
| `weg-shared-layout/menus-data` | WEG21 API types (`MenusData`, …) |
|
|
98
|
-
| `weg-shared-layout/layout-data` | `<weg-header>` / `<weg-footer>` types (`LayoutData`, …) |
|
|
99
|
-
| `weg-shared-layout/weg21-bootstrap.json` | `GET /api/v1/weg21` schema sample |
|
|
100
|
-
| `weg-shared-layout/weg21-menus.json` | `GET /api/v1/weg21/menus` schema sample |
|
|
101
|
-
| `weg-shared-layout/weg-header` / `weg-footer` | Side-effect tag registration |
|
|
102
|
-
| `weg-shared-layout/styles/container.css` | Shared `.container` width and gutter utility |
|
|
103
|
-
|
|
104
|
-
## Documentation
|
|
105
|
-
|
|
106
|
-
Full index: **[docs/README.md](./docs/README.md)**.
|
|
107
|
-
|
|
108
|
-
| Guide | Doc |
|
|
109
|
-
| --- | --- |
|
|
110
|
-
| Angular 16 | [docs/angular.md](./docs/angular.md) |
|
|
111
|
-
| Angular 16 demo (runnable) | [demo/angular16/README.md](./demo/angular16/README.md) |
|
|
112
|
-
| React (SPA, client-only) | [docs/react.md](./docs/react.md) |
|
|
113
|
-
| Next.js (App Router) | [docs/nextjs.md](./docs/nextjs.md) |
|
|
114
|
-
| Plain HTML / vanilla JS | [docs/vanilla.md](./docs/vanilla.md) |
|
|
115
|
-
| Publishing (maintainers) | [docs/publishing.md](./docs/publishing.md) |
|
|
116
|
-
|
|
117
|
-
## Publishing (maintainers)
|
|
118
|
-
|
|
119
|
-
**`npm publish` does not run `npm run build` by itself** — it packs what is on disk. This package uses a **`prepack`** script so a full Stencil build runs before every `npm pack` / `npm publish`, avoiding incomplete tarballs.
|
|
120
|
-
|
|
121
|
-
Details, checklist, and CI notes: **[docs/publishing.md](./docs/publishing.md)**.
|
|
1
|
+
# weg-shared-layout
|
|
2
|
+
|
|
3
|
+
> Shared layout Web Components.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i weg-shared-layout
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## How it works
|
|
12
|
+
|
|
13
|
+
`<weg-header>` and `<weg-footer>` are **presentational** Web Components: they do **not** fetch data.
|
|
14
|
+
|
|
15
|
+
Load layout from the **WEG CMS WEG21 API**, then pass the mapped object to `layout` on each tag:
|
|
16
|
+
|
|
17
|
+
| Endpoint | Purpose |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `GET https://warwickemploymentgroup.com/api/v1/weg21` | Logo URLs, footer social + legal copy |
|
|
20
|
+
| `GET …/api/v1/weg21/menus` | Header (`ext` / `int`) and footer link columns |
|
|
21
|
+
|
|
22
|
+
Both require the `wcms-api-key` header. Use `fetchWeg21Layout` from `weg-shared-layout/menus`:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { fetchWeg21Layout } from 'weg-shared-layout/menus';
|
|
26
|
+
|
|
27
|
+
const layout = await fetchWeg21Layout({
|
|
28
|
+
apiKey: process.env.WCMS_API_KEY,
|
|
29
|
+
});
|
|
30
|
+
// layout.header.menu, layout.footer.menu, layout.footer.social, …
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
[`weg21-bootstrap.json`](src/assets/weg21-bootstrap.json) and [`weg21-menus.json`](src/assets/weg21-menus.json) mirror the **WEG21 API response schemas** (`GET /api/v1/weg21` and `/menus`). Map to `layout` with `dummyWeg21LayoutData()` or `menusToLayoutData`.
|
|
34
|
+
|
|
35
|
+
### Layout shape (abbreviated)
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"header": {
|
|
40
|
+
"menu": [
|
|
41
|
+
{ "label": "Find a job", "items": [{ "label": "Graduates", "href": "…" }] },
|
|
42
|
+
{ "label": "Sign in", "href": "…" }
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"footer": {
|
|
46
|
+
"menu": [[{ "label": "About WEG", "href": "…" }]],
|
|
47
|
+
"social": [{ "platform": "LinkedIn", "href": "…" }],
|
|
48
|
+
"credits": "…",
|
|
49
|
+
"copyright": "…"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Field | Used when | Notes |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `header.logoSrc` | Signed out | Optional CMS logo URL; bundled PNG if omitted |
|
|
57
|
+
| `header.logoHref` | Always | Optional logo link URL; WEG homepage if omitted |
|
|
58
|
+
| `header.menu` | Signed out | Groups use `items`; flat links use `href` |
|
|
59
|
+
| `footer.menu` | Always | `LayoutLink[][]` — one column per inner array |
|
|
60
|
+
| `footer.social` | Always | LinkedIn, Instagram, TikTok, or YouTube |
|
|
61
|
+
| `footer.credits` / `footer.copyright` | Always | Legal copy |
|
|
62
|
+
|
|
63
|
+
### Auth (Sign in / Sign out)
|
|
64
|
+
|
|
65
|
+
**Signed out**: renders `header.menu`. Sign-in is a normal link — add `{ "label": "Sign in", "href": "…" }` like Register or Career advice. The header recognizes it by label or login URL and follows `href` on click.
|
|
66
|
+
|
|
67
|
+
**Signed in** (`signed-in` true): ignores CMS `header.menu` and shows built-in Find a job, Dashboard, Manage Account, and Sign out.
|
|
68
|
+
|
|
69
|
+
Set **`signed-in`** from your app session state. Pass **`user-name`** for Manage Account. Pass **`account-base-url`** when account links should point at a non-production portal. Pass **`current-path`** (e.g. `/career-advice/my-article`) to highlight the active nav item. **Sign out** emits **`wegAuthClick`** — the host must call `event.preventDefault()` and run your logout flow (API call, clear session, redirect).
|
|
70
|
+
|
|
71
|
+
### Nav active state
|
|
72
|
+
|
|
73
|
+
| Link type | Match rule |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| Flat nav link | Prefix — `/career-advice` matches `/career-advice/foo` |
|
|
76
|
+
| Dropdown child | Exact pathname (+ query when href includes `?`) |
|
|
77
|
+
| Dropdown parent | Active background when any child matches |
|
|
78
|
+
| Sign in / Sign out | Never highlighted |
|
|
79
|
+
|
|
80
|
+
Active links use **`weg-purple-200`** (`#CDCFF8`). Omit `current-path` to disable active styling.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
header.addEventListener('wegAuthClick', async (event) => {
|
|
84
|
+
if (event.detail.action !== 'sign-out') return;
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
await logout();
|
|
87
|
+
window.location.assign('/');
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Package imports (TypeScript / bundlers)
|
|
92
|
+
|
|
93
|
+
| Subpath | Use |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `weg-shared-layout/loader` | `defineCustomElements()` — **recommended** |
|
|
96
|
+
| `weg-shared-layout/menus` | `fetchWeg21Layout`, `menusToLayoutData` |
|
|
97
|
+
| `weg-shared-layout/menus-data` | WEG21 API types (`MenusData`, …) |
|
|
98
|
+
| `weg-shared-layout/layout-data` | `<weg-header>` / `<weg-footer>` types (`LayoutData`, …) |
|
|
99
|
+
| `weg-shared-layout/weg21-bootstrap.json` | `GET /api/v1/weg21` schema sample |
|
|
100
|
+
| `weg-shared-layout/weg21-menus.json` | `GET /api/v1/weg21/menus` schema sample |
|
|
101
|
+
| `weg-shared-layout/weg-header` / `weg-footer` | Side-effect tag registration |
|
|
102
|
+
| `weg-shared-layout/styles/container.css` | Shared `.container` width and gutter utility |
|
|
103
|
+
|
|
104
|
+
## Documentation
|
|
105
|
+
|
|
106
|
+
Full index: **[docs/README.md](./docs/README.md)**.
|
|
107
|
+
|
|
108
|
+
| Guide | Doc |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| Angular 16 | [docs/angular.md](./docs/angular.md) |
|
|
111
|
+
| Angular 16 demo (runnable) | [demo/angular16/README.md](./demo/angular16/README.md) |
|
|
112
|
+
| React (SPA, client-only) | [docs/react.md](./docs/react.md) |
|
|
113
|
+
| Next.js (App Router) | [docs/nextjs.md](./docs/nextjs.md) |
|
|
114
|
+
| Plain HTML / vanilla JS | [docs/vanilla.md](./docs/vanilla.md) |
|
|
115
|
+
| Publishing (maintainers) | [docs/publishing.md](./docs/publishing.md) |
|
|
116
|
+
|
|
117
|
+
## Publishing (maintainers)
|
|
118
|
+
|
|
119
|
+
**`npm publish` does not run `npm run build` by itself** — it packs what is on disk. This package uses a **`prepack`** script so a full Stencil build runs before every `npm pack` / `npm publish`, avoiding incomplete tarballs.
|
|
120
|
+
|
|
121
|
+
Details, checklist, and CI notes: **[docs/publishing.md](./docs/publishing.md)**.
|
package/src/types/menus-data.ts
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WEG21 API types — mirrors wegcms-v2 `src/weg-shared-layout/menus-types.ts`.
|
|
3
|
-
* @see GET /api/v1/weg21
|
|
4
|
-
* @see GET /api/v1/weg21/menus
|
|
5
|
-
*/
|
|
6
|
-
export type LayoutPlatform = 'LinkedIn' | 'Instagram' | 'TikTok' | 'YouTube';
|
|
7
|
-
|
|
8
|
-
export type LayoutSocialLink = {
|
|
9
|
-
platform: LayoutPlatform;
|
|
10
|
-
href: string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type MenuItemProps = {
|
|
14
|
-
label: string;
|
|
15
|
-
href?: string;
|
|
16
|
-
items?: MenuItemProps[];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type HeaderMenuProps = {
|
|
20
|
-
ext: MenuItemProps[];
|
|
21
|
-
int: MenuItemProps[];
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export type FooterMenuProps = MenuItemProps[][];
|
|
25
|
-
|
|
26
|
-
/** `GET /api/v1/weg21/menus` response body. */
|
|
27
|
-
export type MenusProps = {
|
|
28
|
-
header: HeaderMenuProps;
|
|
29
|
-
footer: FooterMenuProps;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type Weg21FooterProps = {
|
|
33
|
-
social_links: LayoutSocialLink[];
|
|
34
|
-
credit: string;
|
|
35
|
-
copyright: string;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/** `GET /api/v1/weg21` response body. */
|
|
39
|
-
export type Weg21BootstrapProps = {
|
|
40
|
-
logo: string;
|
|
41
|
-
favicon: string;
|
|
42
|
-
menus: string;
|
|
43
|
-
footer: Weg21FooterProps;
|
|
44
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* WEG21 API types — mirrors wegcms-v2 `src/weg-shared-layout/menus-types.ts`.
|
|
3
|
+
* @see GET /api/v1/weg21
|
|
4
|
+
* @see GET /api/v1/weg21/menus
|
|
5
|
+
*/
|
|
6
|
+
export type LayoutPlatform = 'LinkedIn' | 'Instagram' | 'TikTok' | 'YouTube';
|
|
7
|
+
|
|
8
|
+
export type LayoutSocialLink = {
|
|
9
|
+
platform: LayoutPlatform;
|
|
10
|
+
href: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type MenuItemProps = {
|
|
14
|
+
label: string;
|
|
15
|
+
href?: string;
|
|
16
|
+
items?: MenuItemProps[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type HeaderMenuProps = {
|
|
20
|
+
ext: MenuItemProps[];
|
|
21
|
+
int: MenuItemProps[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type FooterMenuProps = MenuItemProps[][];
|
|
25
|
+
|
|
26
|
+
/** `GET /api/v1/weg21/menus` response body. */
|
|
27
|
+
export type MenusProps = {
|
|
28
|
+
header: HeaderMenuProps;
|
|
29
|
+
footer: FooterMenuProps;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type Weg21FooterProps = {
|
|
33
|
+
social_links: LayoutSocialLink[];
|
|
34
|
+
credit: string;
|
|
35
|
+
copyright: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** `GET /api/v1/weg21` response body. */
|
|
39
|
+
export type Weg21BootstrapProps = {
|
|
40
|
+
logo: string;
|
|
41
|
+
favicon: string;
|
|
42
|
+
menus: string;
|
|
43
|
+
footer: Weg21FooterProps;
|
|
44
|
+
};
|