weg-shared-layout 0.0.4 → 0.0.5
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.
|
@@ -23,7 +23,7 @@ const MyComponent = class {
|
|
|
23
23
|
return format(this.first, this.middle, this.last);
|
|
24
24
|
}
|
|
25
25
|
render() {
|
|
26
|
-
return h("div", { key: '
|
|
26
|
+
return h("div", { key: '5452c3b9c97f8879dbc26b788d1fa79409846ff0' }, "Hello, world! I'm ", this.getText());
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
MyComponent.style = myComponentCss();
|
|
@@ -154,7 +154,7 @@ const WegFooter = class {
|
|
|
154
154
|
return (h("div", { class: "standard__links" }, links.map((l) => (h("a", { class: "footer-link", href: l.href }, l.label)))));
|
|
155
155
|
}
|
|
156
156
|
render() {
|
|
157
|
-
return (h("footer", { key: '
|
|
157
|
+
return (h("footer", { key: 'b5440fe948f8a4207b20d8e380ab50f559890440', class: "footer" }, h("div", { key: '2f4757c3a52203a89b53fa358513d832f153bfa2', class: "container" }, this.renderSocialLinks(), h("div", { key: '4ee53f39a16dab3739c70dadcaadb15602f08ce9', class: "standard" }, this.renderStandardLinks(), this.renderLegalText()))));
|
|
158
158
|
}
|
|
159
159
|
static get watchers() { return {
|
|
160
160
|
"data": [{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weg-shared-layout",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Shared layout Web Components built with Stencil",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"import": "./loader/index.js",
|
|
26
26
|
"require": "./loader/index.cjs",
|
|
27
27
|
"types": "./loader/index.d.ts"
|
|
28
|
-
}
|
|
28
|
+
},
|
|
29
|
+
"./dummy-data.json": "./src/assets/dummy-data.json"
|
|
29
30
|
},
|
|
30
31
|
"repository": {
|
|
31
32
|
"type": "git",
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
"homepage": "https://github.com/jobsac/weg-shared-layout#readme",
|
|
38
39
|
"files": [
|
|
39
40
|
"dist/",
|
|
40
|
-
"loader/"
|
|
41
|
+
"loader/",
|
|
42
|
+
"src/assets/dummy-data.json"
|
|
41
43
|
],
|
|
42
44
|
"scripts": {
|
|
43
45
|
"build": "stencil build",
|
package/readme.md
CHANGED
|
@@ -12,62 +12,28 @@ npm i weg-shared-layout
|
|
|
12
12
|
|
|
13
13
|
## How it works
|
|
14
14
|
|
|
15
|
-
`<weg-footer>` is a **
|
|
15
|
+
`<weg-footer>` is a **presentational** Web Component: it does **not** fetch data. Your app loads layout data however you like (REST, GraphQL, SSR, etc.), then passes the object into the component via the **`data` property** (not a string HTML attribute).
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
The payload shape matches the sample file **`dummy-data.json`**, shipped with the package:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- **Import:** `import layout from 'weg-shared-layout/dummy-data.json'` (enable `resolveJsonModule` in TypeScript if needed).
|
|
20
|
+
- **In this repo:** [`src/assets/dummy-data.json`](src/assets/dummy-data.json)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
GET https://weg-payload-test.vercel.app/api/layout
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Response shape:
|
|
28
|
-
|
|
29
|
-
```json
|
|
30
|
-
{
|
|
31
|
-
"header": {},
|
|
32
|
-
"footer": {
|
|
33
|
-
"social": [
|
|
34
|
-
{ "platform": "LinkedIn", "href": "https://www.linkedin.com/" },
|
|
35
|
-
{ "platform": "Instagram", "href": "https://www.instagram.com/" },
|
|
36
|
-
{ "platform": "TikTok", "href": "https://www.tiktok.com/" },
|
|
37
|
-
{ "platform": "YouTube", "href": "https://www.youtube.com/" }
|
|
38
|
-
],
|
|
39
|
-
"standardLinks": [
|
|
40
|
-
{ "label": "About Us", "href": "/about" },
|
|
41
|
-
{ "label": "Privacy Policy", "href": "/privacy" },
|
|
42
|
-
{ "label": "Terms of Use", "href": "/terms" },
|
|
43
|
-
{ "label": "Cookie Policy", "href": "/cookies" },
|
|
44
|
-
{ "label": "Accessibility Statement", "href": "/accessibility" }
|
|
45
|
-
],
|
|
46
|
-
"credits": "Warwick Employment Group is a department of the Campus and Commercial Services Group at the University of Warwick.",
|
|
47
|
-
"copyright": "Copyright © Warwick Employment Group."
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Only `social.platform` values of `LinkedIn`, `Instagram`, `TikTok`, and `YouTube` render an icon. Items with missing/invalid fields are silently dropped.
|
|
22
|
+
Use that JSON as fixture data to see the footer working, or as a reference for your own API responses. Only `social.platform` values `LinkedIn`, `Instagram`, `TikTok`, and `YouTube` render an icon; items with missing or invalid fields are dropped.
|
|
53
23
|
|
|
54
24
|
## Using in Angular
|
|
55
25
|
|
|
56
|
-
|
|
26
|
+
Assumes Angular 17+ with **standalone** components (default for `ng new`).
|
|
57
27
|
|
|
58
|
-
### 1. Install
|
|
28
|
+
### 1. Install
|
|
59
29
|
|
|
60
30
|
```bash
|
|
61
31
|
npm i weg-shared-layout
|
|
62
|
-
# or: pnpm add weg-shared-layout
|
|
63
|
-
# or: yarn add weg-shared-layout
|
|
64
32
|
```
|
|
65
33
|
|
|
66
|
-
### 2. Register
|
|
67
|
-
|
|
68
|
-
Stencil ships a loader that calls `customElements.define()` for every component in the package. Call it **once** before Angular bootstraps your app, otherwise the browser sees `<weg-footer>` as an unknown element and renders nothing.
|
|
34
|
+
### 2. Register custom elements (once, before bootstrap)
|
|
69
35
|
|
|
70
|
-
|
|
36
|
+
In `src/main.ts`, call `defineCustomElements()` **before** `bootstrapApplication` so the browser recognises `<weg-footer>`.
|
|
71
37
|
|
|
72
38
|
```ts
|
|
73
39
|
import { bootstrapApplication } from '@angular/platform-browser';
|
|
@@ -76,50 +42,26 @@ import { defineCustomElements } from 'weg-shared-layout/loader';
|
|
|
76
42
|
import { appConfig } from './app/app.config';
|
|
77
43
|
import { App } from './app/app';
|
|
78
44
|
|
|
79
|
-
// MUST run before bootstrapApplication so the browser recognises <weg-footer>
|
|
80
|
-
// by the time Angular's renderer touches the DOM.
|
|
81
45
|
defineCustomElements();
|
|
82
46
|
|
|
83
47
|
bootstrapApplication(App, appConfig).catch((err) => console.error(err));
|
|
84
48
|
```
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
### 3. Allow custom elements in templates
|
|
87
51
|
|
|
88
|
-
|
|
52
|
+
Add `schemas: [CUSTOM_ELEMENTS_SCHEMA]` to every `@Component` whose template uses `<weg-footer>` (it does not cascade from the root through `router-outlet` children).
|
|
89
53
|
|
|
90
|
-
|
|
54
|
+
### 4. Pass data with property binding
|
|
91
55
|
|
|
92
|
-
|
|
93
|
-
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
|
94
|
-
import { provideHttpClient } from '@angular/common/http';
|
|
95
|
-
import { provideRouter } from '@angular/router';
|
|
96
|
-
|
|
97
|
-
import { routes } from './app.routes';
|
|
98
|
-
|
|
99
|
-
export const appConfig: ApplicationConfig = {
|
|
100
|
-
providers: [
|
|
101
|
-
provideBrowserGlobalErrorListeners(),
|
|
102
|
-
provideRouter(routes),
|
|
103
|
-
provideHttpClient(),
|
|
104
|
-
],
|
|
105
|
-
};
|
|
106
|
-
```
|
|
56
|
+
Use **`[data]="..."`** so Angular sets the element’s JavaScript `data` property (Stencil `@Prop()`), not an HTML attribute.
|
|
107
57
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Without this, Angular's template compiler throws:
|
|
111
|
-
|
|
112
|
-
> `'weg-footer' is not a known element: ... If 'weg-footer' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@Component.schemas' of this component to suppress this message.`
|
|
113
|
-
|
|
114
|
-
In **standalone components** (default in Angular 17+), add `schemas: [CUSTOM_ELEMENTS_SCHEMA]` to the `@Component` decorator of **every component that uses `<weg-footer>` in its template**. Easiest is to add it to your root `App` component:
|
|
58
|
+
Example with the bundled sample payload:
|
|
115
59
|
|
|
116
60
|
```ts
|
|
117
61
|
// src/app/app.ts
|
|
118
|
-
import { Component, CUSTOM_ELEMENTS_SCHEMA,
|
|
119
|
-
import { HttpClient } from '@angular/common/http';
|
|
62
|
+
import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';
|
|
120
63
|
import { RouterOutlet } from '@angular/router';
|
|
121
|
-
|
|
122
|
-
const LAYOUT_API = 'https://weg-payload-test.vercel.app/api/layout';
|
|
64
|
+
import layoutFixture from 'weg-shared-layout/dummy-data.json';
|
|
123
65
|
|
|
124
66
|
@Component({
|
|
125
67
|
selector: 'app-root',
|
|
@@ -128,201 +70,87 @@ const LAYOUT_API = 'https://weg-payload-test.vercel.app/api/layout';
|
|
|
128
70
|
templateUrl: './app.html',
|
|
129
71
|
styleUrl: './app.css',
|
|
130
72
|
})
|
|
131
|
-
export class App
|
|
132
|
-
protected readonly layoutData = signal
|
|
133
|
-
|
|
134
|
-
private readonly http = inject(HttpClient);
|
|
135
|
-
|
|
136
|
-
ngOnInit(): void {
|
|
137
|
-
this.http.get(LAYOUT_API).subscribe({
|
|
138
|
-
next: (data) => this.layoutData.set(data),
|
|
139
|
-
error: (err) => console.error('Failed to load layout data', err),
|
|
140
|
-
});
|
|
141
|
-
}
|
|
73
|
+
export class App {
|
|
74
|
+
protected readonly layoutData = signal(layoutFixture);
|
|
142
75
|
}
|
|
143
76
|
```
|
|
144
77
|
|
|
145
|
-
> `CUSTOM_ELEMENTS_SCHEMA` is **per-component** in standalone Angular. If you use `<weg-footer>` inside a child component's template, that child must declare `schemas: [CUSTOM_ELEMENTS_SCHEMA]` too. It does **not** cascade through `<router-outlet />`.
|
|
146
|
-
|
|
147
|
-
### 5. Pass the data into `<weg-footer>` via the `[data]` binding
|
|
148
|
-
|
|
149
|
-
In `src/app/app.html`:
|
|
150
|
-
|
|
151
78
|
```html
|
|
79
|
+
<!-- src/app/app.html -->
|
|
152
80
|
<router-outlet />
|
|
153
|
-
|
|
154
81
|
<weg-footer [data]="layoutData()"></weg-footer>
|
|
155
82
|
```
|
|
156
83
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
#### Why `[data]` and not `data-src` or `[attr.data]`
|
|
160
|
-
|
|
161
|
-
- `[data]="..."` is Angular's **property binding** — it sets the JS property `data` on the underlying DOM element. Stencil exposes `@Prop()` values as JS properties, so this passes the object straight through. **This is what you want.**
|
|
162
|
-
- `[attr.data]="..."` would set an HTML attribute, which is always a string — Angular would call `JSON.stringify(layoutData)` for you, the component would have to parse it back, and you'd lose type fidelity. Avoid unless you have a reason.
|
|
163
|
-
- Plain `data="..."` only works for a static string literal and would have the same parsing cost — fine for testing, not for real data.
|
|
164
|
-
|
|
165
|
-
### 6. Verify it works
|
|
166
|
-
|
|
167
|
-
After running `ng serve`, open the page and check:
|
|
168
|
-
|
|
169
|
-
1. The dark footer bar renders at the bottom of the page.
|
|
170
|
-
2. DevTools → Network tab shows a `200 OK` to `https://weg-payload-test.vercel.app/api/layout`.
|
|
171
|
-
3. DevTools → Elements → click `<weg-footer>` → in the Console, type `$0.data` — you should see the JSON object you fetched.
|
|
172
|
-
4. Expand `<weg-footer>` in the Elements panel — you should see a `#shadow-root (open)` containing the actual `<footer>` markup.
|
|
84
|
+
In production, replace `layoutFixture` with data from your own services; keep the same object shape as `dummy-data.json`.
|
|
173
85
|
|
|
174
86
|
### Troubleshooting
|
|
175
87
|
|
|
176
88
|
| Symptom | Cause / fix |
|
|
177
89
|
| --- | --- |
|
|
178
|
-
| `'weg-footer' is not a known element`
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
| `NullInjectorError: No provider for HttpClient` | You forgot `provideHttpClient()` in `app.config.ts`. |
|
|
182
|
-
| CORS error in the console | The API host must allow your origin. Either fix CORS on the backend, or proxy through Angular's dev proxy (`proxy.conf.json`) so the call becomes same-origin. |
|
|
183
|
-
| Footer doesn't update after data changes | Make sure you're using `[data]="layoutData()"` with a signal (or `[data]="layoutData$ | async"` with an Observable) so Angular pushes new values into the element. |
|
|
184
|
-
| Works locally, fails in SSR (`document is not defined`) | `defineCustomElements()` touches `window` / `customElements`. Wrap in `if (typeof window !== 'undefined') { ... }` or use `isPlatformBrowser(platformId)` in `main.ts`. |
|
|
185
|
-
| TypeScript: `Property 'weg-footer' does not exist on type 'HTMLElementTagNameMap'` | See the typings section below. |
|
|
186
|
-
|
|
187
|
-
### TypeScript typings (Angular)
|
|
90
|
+
| `'weg-footer' is not a known element` | Add `schemas: [CUSTOM_ELEMENTS_SCHEMA]` on the component whose template contains `<weg-footer>`. |
|
|
91
|
+
| Footer missing or empty box | `defineCustomElements()` not called before bootstrap, or `data` not set / wrong shape — compare with `dummy-data.json`. |
|
|
92
|
+
| SSR: `document is not defined` | Guard `defineCustomElements()` with `typeof window !== 'undefined'` or `isPlatformBrowser`. |
|
|
188
93
|
|
|
189
|
-
|
|
94
|
+
### TypeScript typings
|
|
190
95
|
|
|
191
96
|
```ts
|
|
192
97
|
/// <reference types="weg-shared-layout/dist/types/components" />
|
|
193
98
|
```
|
|
194
99
|
|
|
195
|
-
### Legacy
|
|
100
|
+
### Legacy `NgModule`
|
|
196
101
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
```ts
|
|
200
|
-
// src/app/app.module.ts
|
|
201
|
-
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
202
|
-
import { HttpClientModule } from '@angular/common/http';
|
|
203
|
-
|
|
204
|
-
@NgModule({
|
|
205
|
-
imports: [HttpClientModule /* ... */],
|
|
206
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
207
|
-
})
|
|
208
|
-
export class AppModule {}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
`defineCustomElements()` in `main.ts` is still required either way. Inject `HttpClient` in your component the same way as the standalone example above.
|
|
102
|
+
Add `CUSTOM_ELEMENTS_SCHEMA` once on the module that declares components using `<weg-footer>`. `defineCustomElements()` in `main.ts` is still required.
|
|
212
103
|
|
|
213
104
|
## Using in React
|
|
214
105
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
npm i weg-shared-layout
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Register custom elements (pick one):
|
|
106
|
+
Register once (for example in your app entry):
|
|
222
107
|
|
|
223
108
|
```ts
|
|
224
|
-
// Option A (recommended): loader registers all components
|
|
225
109
|
import { defineCustomElements } from 'weg-shared-layout/loader';
|
|
226
110
|
|
|
227
111
|
defineCustomElements();
|
|
228
112
|
```
|
|
229
113
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
// Option B: import package bundle (also registers, depending on output target configuration)
|
|
234
|
-
import 'weg-shared-layout';
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
Then fetch the data in your component and pass it in via a ref (because the `data` prop is an object, not a string attribute):
|
|
238
|
-
|
|
239
|
-
```tsx
|
|
240
|
-
import { useEffect, useRef, useState } from 'react';
|
|
241
|
-
import 'weg-shared-layout/weg-footer';
|
|
242
|
-
|
|
243
|
-
const LAYOUT_API = 'https://weg-payload-test.vercel.app/api/layout';
|
|
244
|
-
|
|
245
|
-
export function SiteFooter() {
|
|
246
|
-
const ref = useRef<HTMLElement>(null);
|
|
247
|
-
const [layout, setLayout] = useState<unknown>(null);
|
|
248
|
-
|
|
249
|
-
useEffect(() => {
|
|
250
|
-
fetch(LAYOUT_API).then((r) => r.json()).then(setLayout);
|
|
251
|
-
}, []);
|
|
252
|
-
|
|
253
|
-
useEffect(() => {
|
|
254
|
-
if (ref.current) (ref.current as any).data = layout;
|
|
255
|
-
}, [layout]);
|
|
256
|
-
|
|
257
|
-
return <weg-footer ref={ref} />;
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
> React (pre-19) sets unknown JSX attributes as HTML attributes, which would stringify your object. Assigning via a ref guarantees you set the JS property. React 19+ handles this correctly without the ref dance.
|
|
262
|
-
|
|
263
|
-
### Next.js (App Router) note
|
|
264
|
-
|
|
265
|
-
Stencil custom elements must be registered **in the browser**. In Next.js `app/` (App Router), don't import/register Stencil components from a Server Component.
|
|
266
|
-
|
|
267
|
-
Instead, register them in a Client Component, for example:
|
|
114
|
+
Pass an object via a **ref** (or use React 19+ property handling) so you set the DOM property, not a string attribute:
|
|
268
115
|
|
|
269
116
|
```tsx
|
|
270
|
-
// app/components/SiteFooter.tsx
|
|
271
|
-
"use client";
|
|
272
|
-
|
|
273
117
|
import { useEffect, useRef, useState } from 'react';
|
|
274
118
|
import 'weg-shared-layout/weg-footer';
|
|
119
|
+
import layoutFixture from 'weg-shared-layout/dummy-data.json';
|
|
275
120
|
|
|
276
121
|
export function SiteFooter() {
|
|
277
|
-
const ref = useRef<HTMLElement>(null);
|
|
278
|
-
const [layout, setLayout] = useState
|
|
122
|
+
const ref = useRef<HTMLElement & { data?: unknown }>(null);
|
|
123
|
+
const [layout, setLayout] = useState(layoutFixture);
|
|
279
124
|
|
|
280
125
|
useEffect(() => {
|
|
281
|
-
|
|
282
|
-
}, []);
|
|
283
|
-
|
|
284
|
-
useEffect(() => {
|
|
285
|
-
if (ref.current) (ref.current as any).data = layout;
|
|
126
|
+
if (ref.current) ref.current.data = layout;
|
|
286
127
|
}, [layout]);
|
|
287
128
|
|
|
288
129
|
return <weg-footer ref={ref} />;
|
|
289
130
|
}
|
|
290
131
|
```
|
|
291
132
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
### React TypeScript typings
|
|
133
|
+
Swap `layoutFixture` / `setLayout` for your own data loading. **Next.js App Router:** register and assign `data` only in a Client Component (`"use client"`).
|
|
295
134
|
|
|
296
|
-
|
|
135
|
+
### React TypeScript
|
|
297
136
|
|
|
298
137
|
```ts
|
|
299
138
|
/// <reference types="weg-shared-layout/dist/types/components" />
|
|
300
139
|
```
|
|
301
140
|
|
|
302
|
-
If your app still complains about JSX intrinsic elements, you can also augment `JSX.IntrinsicElements` in that same file (varies by React/TS setup).
|
|
303
|
-
|
|
304
141
|
## Plain HTML / vanilla JS
|
|
305
142
|
|
|
306
|
-
|
|
143
|
+
With a bundler that resolves `node_modules` imports:
|
|
307
144
|
|
|
308
145
|
```html
|
|
309
146
|
<weg-footer id="footer"></weg-footer>
|
|
310
|
-
|
|
311
147
|
<script type="module">
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
</script>
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
You can also pass the JSON as a string attribute — useful for SSR or static HTML where you don't want a runtime fetch:
|
|
148
|
+
import { defineCustomElements } from 'weg-shared-layout/loader';
|
|
149
|
+
import layout from 'weg-shared-layout/dummy-data.json';
|
|
318
150
|
|
|
319
|
-
|
|
320
|
-
|
|
151
|
+
defineCustomElements();
|
|
152
|
+
document.getElementById('footer').data = layout;
|
|
153
|
+
</script>
|
|
321
154
|
```
|
|
322
155
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
Because the host app calls the API directly, **the API must respond with `Access-Control-Allow-Origin` headers** that include your app's origin. If you hit a CORS error in the browser console, either:
|
|
326
|
-
|
|
327
|
-
- Fix CORS on the API host, **or**
|
|
328
|
-
- Proxy the call through your own host. Angular: configure `proxy.conf.json` so `/api/layout` is rewritten to the production URL. Next.js: add a route handler that re-fetches and returns the JSON.
|
|
156
|
+
Otherwise, copy `dummy-data.json` to your static assets, `fetch` it, parse JSON, then assign **`element.data`**. You can also pass a JSON string on the **`data` attribute**; the component parses it the same way as an object `data` property.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"header": {},
|
|
3
|
+
"footer": {
|
|
4
|
+
"social": [
|
|
5
|
+
{ "platform": "LinkedIn", "href": "https://www.linkedin.com/" },
|
|
6
|
+
{ "platform": "Instagram", "href": "https://www.instagram.com/" },
|
|
7
|
+
{ "platform": "TikTok", "href": "https://www.tiktok.com/" },
|
|
8
|
+
{ "platform": "YouTube", "href": "https://www.youtube.com/" }
|
|
9
|
+
],
|
|
10
|
+
"standardLinks": [
|
|
11
|
+
{ "label": "About Us", "href": "/about" },
|
|
12
|
+
{ "label": "Privacy Policy", "href": "/privacy" },
|
|
13
|
+
{ "label": "Terms of Use", "href": "/terms" },
|
|
14
|
+
{ "label": "Cookie Policy", "href": "/cookies" },
|
|
15
|
+
{ "label": "Accessibility Statement", "href": "/accessibility" }
|
|
16
|
+
],
|
|
17
|
+
"credits": "Warwick Employment Group is a department of the Campus and Commercial Services Group at the University of Warwick.",
|
|
18
|
+
"copyright": "Copyright © Warwick Employment Group."
|
|
19
|
+
}
|
|
20
|
+
}
|