@ons/design-system 44.0.2 → 44.1.1

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.
Files changed (44) hide show
  1. package/components/modal/_macro.njk +23 -0
  2. package/components/modal/_modal.scss +32 -0
  3. package/components/modal/modal.dom.js +14 -0
  4. package/components/modal/modal.js +104 -0
  5. package/components/timeout-modal/_macro.njk +26 -0
  6. package/components/timeout-modal/timeout.dom.js +16 -0
  7. package/components/timeout-modal/timeout.js +289 -0
  8. package/favicons/census/cy/android-chrome-192x192.png +0 -0
  9. package/favicons/census/cy/android-chrome-512x512.png +0 -0
  10. package/favicons/census/cy/apple-touch-icon.png +0 -0
  11. package/favicons/census/cy/browserconfig.xml +12 -0
  12. package/favicons/census/cy/favicon-16x16.png +0 -0
  13. package/favicons/census/cy/favicon-32x32.png +0 -0
  14. package/favicons/census/cy/favicon.ico +0 -0
  15. package/favicons/census/cy/manifest.json +20 -0
  16. package/favicons/census/cy/mstitle-150x150.png +0 -0
  17. package/favicons/census/cy/mstitle-310x150.png +0 -0
  18. package/favicons/census/cy/mstitle-310x310.png +0 -0
  19. package/favicons/census/cy/mstitle-70x70.png +0 -0
  20. package/favicons/census/cy/opengraph.png +0 -0
  21. package/favicons/census/cy/safari-pinned-tab.svg +3 -0
  22. package/favicons/census/cy/site.webmanifest +19 -0
  23. package/favicons/census/cy/twitter.png +0 -0
  24. package/favicons/census/en/android-chrome-192x192.png +0 -0
  25. package/favicons/census/en/android-chrome-512x512.png +0 -0
  26. package/favicons/census/en/apple-touch-icon.png +0 -0
  27. package/favicons/census/en/browserconfig.xml +12 -0
  28. package/favicons/census/en/favicon-16x16.png +0 -0
  29. package/favicons/census/en/favicon-32x32.png +0 -0
  30. package/favicons/census/en/favicon.ico +0 -0
  31. package/favicons/census/en/manifest.json +20 -0
  32. package/favicons/census/en/mstitle-150x150.png +0 -0
  33. package/favicons/census/en/mstitle-310x150.png +0 -0
  34. package/favicons/census/en/mstitle-310x310.png +0 -0
  35. package/favicons/census/en/mstitle-70x70.png +0 -0
  36. package/favicons/census/en/opengraph.png +0 -0
  37. package/favicons/census/en/safari-pinned-tab.svg +3 -0
  38. package/favicons/census/en/site.webmanifest +19 -0
  39. package/favicons/census/en/twitter.png +0 -0
  40. package/favicons/census/ni/favicon.ico +0 -0
  41. package/package.json +3 -3
  42. package/scripts/main.es5.js +2 -2
  43. package/scripts/main.js +1 -1
  44. package/src/js/domready.js +17 -0
@@ -0,0 +1,23 @@
1
+ {% macro onsModal(params) %}
2
+ {% set modalID = params.id | default('dialog') %}
3
+ <dialog class="ons-modal ons-js-modal {{ params.classes }}"
4
+ id="{{ modalID }}"
5
+ role="dialog"
6
+ aria-labelledby="ons-modal-title"
7
+ {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
8
+ >
9
+ <h1 id="ons-modal-title" class="ons-modal__title">
10
+ {{ params.title }}
11
+ </h1>
12
+ <div class="ons-modal__body">
13
+ {{ (params.body if params else "") | safe }}{{ caller() if caller }}
14
+ </div>
15
+ {% if params.btnText %}
16
+ {% from "components/button/_macro.njk" import onsButton %}
17
+ {{ onsButton({
18
+ "text": params.btnText,
19
+ "classes": "ons-js-modal-btn ons-u-mt-s"
20
+ }) }}
21
+ {% endif %}
22
+ </dialog>
23
+ {% endmacro %}
@@ -0,0 +1,32 @@
1
+ $backdrop-colour: rgba(0, 0, 0, 0.8);
2
+
3
+ .ons-modal {
4
+ border: none;
5
+ border-radius: 0.4rem;
6
+ box-shadow: 0 0 7px 0 #000;
7
+ display: none;
8
+ margin-left: 2rem;
9
+ margin-right: 2rem;
10
+ max-width: 500px;
11
+ padding: 2rem;
12
+ width: auto;
13
+
14
+ @media screen and (min-width: 600px) {
15
+ margin-left: auto;
16
+ margin-right: auto;
17
+ width: 100%;
18
+ }
19
+
20
+ &::backdrop {
21
+ backdrop-filter: blur(3px);
22
+ background: $backdrop-colour;
23
+ }
24
+
25
+ & + .backdrop {
26
+ background: $backdrop-colour;
27
+ }
28
+ }
29
+
30
+ .ons-modal-overlay {
31
+ overflow: hidden;
32
+ }
@@ -0,0 +1,14 @@
1
+ import domready from '../../js/domready';
2
+
3
+ async function modals() {
4
+ const modals = [...document.querySelectorAll('.ons-js-modal')];
5
+ const timeouts = [...document.querySelectorAll('.ons-js-timeout-modal')];
6
+
7
+ if (modals.length && !timeouts.length) {
8
+ const Modal = (await import('./modal')).default;
9
+
10
+ modals.forEach(component => new Modal(component));
11
+ }
12
+ }
13
+
14
+ domready(modals);
@@ -0,0 +1,104 @@
1
+ import dialogPolyfill from 'dialog-polyfill';
2
+
3
+ const overLayClass = 'ons-modal-overlay';
4
+
5
+ export default class Modal {
6
+ constructor(component) {
7
+ this.component = component;
8
+ this.launcher = document.querySelector(`[data-modal-id=${component.id}]`);
9
+ this.closeButton = component.querySelector('.ons-js-modal-btn');
10
+ this.lastFocusedEl = null;
11
+
12
+ this.initialise();
13
+ }
14
+
15
+ initialise() {
16
+ if (!this.dialogSupported()) {
17
+ /* istanbul ignore next */
18
+ return;
19
+ }
20
+
21
+ if (this.launcher) {
22
+ this.launcher.addEventListener('click', this.openDialog.bind(this));
23
+ }
24
+
25
+ if (this.closeButton) {
26
+ this.closeButton.addEventListener('click', this.closeDialog.bind(this));
27
+ }
28
+ }
29
+
30
+ dialogSupported() {
31
+ if (typeof HTMLDialogElement === 'function') {
32
+ return true;
33
+ } else {
34
+ try {
35
+ dialogPolyfill.registerDialog(this.component);
36
+ return true;
37
+ } catch (error) {
38
+ /* istanbul ignore next */
39
+ return false;
40
+ }
41
+ }
42
+ }
43
+
44
+ openDialog(event) {
45
+ if (!this.isDialogOpen()) {
46
+ this.component.classList.add('ons-u-db');
47
+ document.querySelector('body').className += ' ' + overLayClass;
48
+ this.makePageContentInert();
49
+ this.saveLastFocusedEl();
50
+ if (event) {
51
+ const modal = document.getElementById(event.target.getAttribute('data-modal-id'));
52
+ modal.showModal();
53
+ } else {
54
+ this.component.showModal();
55
+ }
56
+ }
57
+ }
58
+
59
+ saveLastFocusedEl() {
60
+ this.lastFocusedEl = document.activeElement;
61
+ if (!this.lastFocusedEl || this.lastFocusedEl === document.body) {
62
+ this.lastFocusedEl = null;
63
+ } else if (document.querySelector) {
64
+ this.lastFocusedEl = document.querySelector(':focus');
65
+ }
66
+ }
67
+
68
+ setFocusOnLastFocusedEl(lastFocusedEl) {
69
+ if (lastFocusedEl) {
70
+ lastFocusedEl.focus();
71
+ }
72
+ }
73
+
74
+ makePageContentInert() {
75
+ if (document.querySelector('.ons-page')) {
76
+ document.querySelector('.ons-page').inert = true;
77
+ document.querySelector('.ons-page').setAttribute('aria-hidden', 'true');
78
+ }
79
+ }
80
+
81
+ removeInertFromPageContent() {
82
+ if (document.querySelector('.ons-page')) {
83
+ document.querySelector('.ons-page').inert = false;
84
+ document.querySelector('.ons-page').setAttribute('aria-hidden', 'false');
85
+ }
86
+ }
87
+
88
+ isDialogOpen() {
89
+ return this.component['open'];
90
+ }
91
+
92
+ closeDialog(event) {
93
+ if (this.isDialogOpen()) {
94
+ if (event) {
95
+ event.preventDefault();
96
+ }
97
+ this.component.classList.remove('ons-u-db');
98
+ document.querySelector('body').classList.remove(overLayClass);
99
+ this.component.close();
100
+ this.setFocusOnLastFocusedEl(this.lastFocusedEl);
101
+ this.removeInertFromPageContent();
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,26 @@
1
+ {% from "components/modal/_macro.njk" import onsModal %}
2
+ {% macro onsTimeoutModal(params) %}
3
+ {% call onsModal({
4
+ "title": params.title,
5
+ "btnText": params.btnText,
6
+ "classes": "ons-js-timeout-modal",
7
+ "attributes": {
8
+ "data-redirect-url": params.redirectUrl,
9
+ "data-timeout-time": params.serverTimeoutTime,
10
+ "data-show-modal-time": params.showModalTimeInSeconds,
11
+ "data-server-session-expiry-endpoint": params.serverSessionExpiryEndpoint,
12
+ "data-countdown-text": params.countdownText,
13
+ "data-redirecting-text": params.redirectingText,
14
+ "data-minutes-text-singular": params.minutesTextSingular,
15
+ "data-minutes-text-plural": params.minutesTextPlural,
16
+ "data-seconds-text-singular": params.secondsTextSingular,
17
+ "data-seconds-text-plural": params.secondsTextPlural,
18
+ "aria-describedby": "timeout-time-remaining"
19
+ }
20
+ })
21
+ %}
22
+ <p>{{ params.textFirstLine }}</p>
23
+ <p class="ons-js-timeout-timer" aria-hidden="true" aria-relevant="additions"></p>
24
+ <p class="ons-js-timeout-timer-acc ons-u-vh" role="status" id="timeout-time-remaining"></p>
25
+ {% endcall %}
26
+ {% endmacro %}
@@ -0,0 +1,16 @@
1
+ import domready from '../../js/domready';
2
+
3
+ async function modals() {
4
+ const timeouts = [...document.querySelectorAll('.ons-js-timeout-modal')];
5
+
6
+ if (timeouts.length) {
7
+ const Timeout = (await import('./timeout')).default;
8
+
9
+ timeouts.forEach(context => {
10
+ let url = context.getAttribute('data-server-session-expiry-endpoint');
11
+ new Timeout(context, url);
12
+ });
13
+ }
14
+ }
15
+
16
+ domready(modals);
@@ -0,0 +1,289 @@
1
+ import Modal from '../modal/modal';
2
+
3
+ export default class Timeout {
4
+ constructor(context, url, time) {
5
+ this.context = context;
6
+ this.sessionExpiryEndpoint = url;
7
+ this.initialExpiryTime = time;
8
+ this.continueButton = context.querySelector('.ons-js-modal-btn');
9
+ this.countdown = context.querySelector('.ons-js-timeout-timer');
10
+ this.accessibleCountdown = context.querySelector('.ons-js-timeout-timer-acc');
11
+ this.timeOutRedirectUrl = context.getAttribute('data-redirect-url');
12
+ this.modalVisibleInMilliseconds = context.getAttribute('data-show-modal-time') * 1000;
13
+
14
+ // Language dependent text strings
15
+ this.minutesTextSingular = context.getAttribute('data-minutes-text-singular');
16
+ this.minutesTextPlural = context.getAttribute('data-minutes-text-plural');
17
+ this.secondsTextSingular = context.getAttribute('data-seconds-text-singular');
18
+ this.secondsTextPlural = context.getAttribute('data-seconds-text-plural');
19
+ this.countdownText = context.getAttribute('data-countdown-text');
20
+ this.redirectingText = context.getAttribute('data-redirecting-text');
21
+
22
+ // Settings
23
+ this.expiryTimeInMilliseconds = 0;
24
+ this.expiryTime = '';
25
+ this.showModalTimeout = null;
26
+ this.timers = [];
27
+ this.timerRunOnce = false;
28
+
29
+ // Create modal instance
30
+ this.modal = new Modal(this.context);
31
+
32
+ // Start module
33
+ this.initialise();
34
+ }
35
+
36
+ async initialise() {
37
+ this.expiryTime = await this.setNewExpiryTime();
38
+ this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(this.expiryTime);
39
+
40
+ this.bindEventListeners();
41
+ }
42
+
43
+ bindEventListeners() {
44
+ window.onload = this.startTimeout();
45
+ window.addEventListener('focus', this.handleWindowFocus.bind(this));
46
+ window.addEventListener('keydown', this.escToClose.bind(this));
47
+ this.continueButton.addEventListener('click', this.closeModalAndRestartTimeout.bind(this));
48
+ this.addThrottledEvents();
49
+ }
50
+
51
+ startTimeout() {
52
+ clearTimeout(this.showModalTimeout);
53
+ this.showModalTimeout = setTimeout(this.openModal.bind(this), this.expiryTimeInMilliseconds - this.modalVisibleInMilliseconds);
54
+ }
55
+
56
+ async openModal() {
57
+ const modalWillOpen = await this.hasExpiryTimeResetInAnotherTab();
58
+ if (modalWillOpen && !this.modal.isDialogOpen()) {
59
+ this.modal.openDialog();
60
+ this.startUiCountdown();
61
+ }
62
+ }
63
+
64
+ async startUiCountdown() {
65
+ this.clearTimers();
66
+ clearInterval(this.shouldModalCloseCheck);
67
+
68
+ this.shouldModalCloseCheck = setInterval(async () => {
69
+ await this.hasExpiryTimeResetInAnotherTab();
70
+ }, 20000);
71
+
72
+ let millseconds = this.modalVisibleInMilliseconds;
73
+ let seconds = millseconds / 1000;
74
+ let timers = this.timers;
75
+ let $this = this;
76
+
77
+ (async function runTimer() {
78
+ const minutesLeft = parseInt(seconds / 60, 10);
79
+ const secondsLeft = parseInt(seconds % 60, 10);
80
+ const timerExpired = minutesLeft < 1 && secondsLeft < 1;
81
+
82
+ const minutesText =
83
+ minutesLeft + ' ' + (minutesLeft >= 2 ? $this.minutesTextPlural : minutesLeft === 1 ? $this.minutesTextSingular : '');
84
+ const secondsText =
85
+ secondsLeft + ' ' + (secondsLeft >= 2 ? $this.secondsTextPlural : secondsLeft === 1 ? $this.secondsTextSingular : '');
86
+
87
+ let timeLeftText =
88
+ $this.countdownText +
89
+ ' <span class="ons-u-fw-b">' +
90
+ (minutesLeft > 0 ? minutesText : '') +
91
+ (minutesLeft > 0 && secondsLeft > 0 ? ' ' : '') +
92
+ (secondsLeft > 0 ? secondsText : '') +
93
+ '</span>.';
94
+
95
+ if (timerExpired) {
96
+ const shouldExpire = await $this.hasExpiryTimeResetInAnotherTab();
97
+
98
+ if (shouldExpire) {
99
+ $this.countdown.innerHTML = '<span class="ons-u-fw-b">' + $this.redirectingText + '</span>';
100
+ $this.accessibleCountdown.innerHTML = $this.redirectingText;
101
+ setTimeout($this.redirect.bind($this), 2000);
102
+ }
103
+ } else {
104
+ seconds--;
105
+ $this.expiryTimeInMilliseconds = seconds * 1000;
106
+ $this.countdown.innerHTML = timeLeftText;
107
+
108
+ if (minutesLeft < 1 && secondsLeft < 20) {
109
+ $this.accessibleCountdown.setAttribute('aria-live', 'assertive');
110
+ }
111
+
112
+ if (!$this.timerRunOnce) {
113
+ $this.accessibleCountdown.innerHTML = timeLeftText;
114
+ $this.timerRunOnce = true;
115
+ } else if (secondsLeft % 15 === 0) {
116
+ $this.accessibleCountdown.innerHTML = timeLeftText;
117
+ }
118
+
119
+ timers.push(setTimeout(runTimer.bind($this), 1000));
120
+ }
121
+ })();
122
+ }
123
+
124
+ async hasExpiryTimeResetInAnotherTab() {
125
+ const checkExpiryTime = await this.getExpiryTime();
126
+
127
+ if (checkExpiryTime != this.expiryTime) {
128
+ this.expiryTime = checkExpiryTime;
129
+ this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(checkExpiryTime);
130
+ this.closeModalAndRestartTimeout(this.expiryTimeInMilliseconds);
131
+ } else {
132
+ return true;
133
+ }
134
+ }
135
+
136
+ closeModalAndRestartTimeout(timeInMilliSeconds) {
137
+ if (typeof timeInMilliSeconds !== 'string') {
138
+ timeInMilliSeconds = false;
139
+ }
140
+ if (this.modal.isDialogOpen()) {
141
+ this.modal.closeDialog();
142
+ }
143
+ this.restartTimeout(timeInMilliSeconds);
144
+ }
145
+
146
+ async restartTimeout(timeInMilliSeconds) {
147
+ this.clearTimers();
148
+ clearInterval(this.shouldModalCloseCheck);
149
+
150
+ if (timeInMilliSeconds) {
151
+ this.expiryTimeInMilliseconds = timeInMilliSeconds;
152
+ } else {
153
+ const createNewExpiryTime = await this.setNewExpiryTime();
154
+ this.expiryTime = createNewExpiryTime;
155
+ this.expiryTimeInMilliseconds = this.convertTimeToMilliSeconds(createNewExpiryTime);
156
+ }
157
+
158
+ this.startTimeout();
159
+ }
160
+
161
+ async handleWindowFocus() {
162
+ if (this.sessionExpiryEndpoint) {
163
+ const canSetNewExpiry = await this.setNewExpiryTime();
164
+ if (!canSetNewExpiry) {
165
+ this.redirect();
166
+ } else {
167
+ this.closeModalAndRestartTimeout();
168
+ }
169
+ }
170
+ }
171
+
172
+ escToClose(event) {
173
+ if (this.modal.isDialogOpen() && event.keyCode === 27) {
174
+ this.closeModalAndRestartTimeout();
175
+ }
176
+ }
177
+
178
+ async setNewExpiryTime() {
179
+ let newExpiryTime;
180
+ if (!this.sessionExpiryEndpoint) {
181
+ // For demo purposes
182
+ const demoTime = new Date(this.initialExpiryTime ? this.initialExpiryTime : Date.now() + 60 * 1000);
183
+ newExpiryTime = new Date(demoTime).toISOString();
184
+ } else {
185
+ newExpiryTime = await this.fetchExpiryTime('PATCH');
186
+ }
187
+ return newExpiryTime;
188
+ }
189
+
190
+ async getExpiryTime() {
191
+ if (this.sessionExpiryEndpoint) {
192
+ const currentExpiryTime = await this.fetchExpiryTime('GET');
193
+ return currentExpiryTime;
194
+ } else {
195
+ // For demo purposes
196
+ return this.expiryTime;
197
+ }
198
+ }
199
+
200
+ async fetchExpiryTime(fetchMethod) {
201
+ let response = await fetch(this.sessionExpiryEndpoint, {
202
+ method: fetchMethod,
203
+ headers: { 'Cache-Control': 'no-cache', 'Content-type': 'application/json; charset=UTF-8' },
204
+ });
205
+ if (!response.ok) {
206
+ this.redirect();
207
+ return false;
208
+ }
209
+
210
+ let json = await response.json();
211
+
212
+ return json.expires_at;
213
+ }
214
+
215
+ convertTimeToMilliSeconds(expiryTime) {
216
+ const time = new Date(expiryTime);
217
+ const calculateTimeInMilliSeconds = Math.abs(time - new Date());
218
+
219
+ return calculateTimeInMilliSeconds;
220
+ }
221
+
222
+ redirect() {
223
+ window.location.replace(this.timeOutRedirectUrl);
224
+ }
225
+
226
+ clearTimers() {
227
+ for (let i = 0; i < this.timers.length; i++) {
228
+ clearTimeout(this.timers[i]);
229
+ }
230
+ }
231
+
232
+ addThrottledEvents() {
233
+ window.onclick = this.throttle(() => {
234
+ /* istanbul ignore next */
235
+ if (!this.modal.isDialogOpen()) {
236
+ this.restartTimeout();
237
+ }
238
+ }, 61000);
239
+
240
+ window.onmousemove = this.throttle(() => {
241
+ /* istanbul ignore next */
242
+ if (!this.modal.isDialogOpen()) {
243
+ this.restartTimeout();
244
+ }
245
+ }, 61000);
246
+
247
+ window.onmousedown = this.throttle(() => {
248
+ /* istanbul ignore next */
249
+ if (!this.modal.isDialogOpen()) {
250
+ this.restartTimeout();
251
+ }
252
+ }, 61000);
253
+
254
+ window.onscroll = this.throttle(() => {
255
+ /* istanbul ignore next */
256
+ if (!this.modal.isDialogOpen()) {
257
+ this.restartTimeout();
258
+ }
259
+ }, 61000);
260
+
261
+ window.onkeypress = this.throttle(() => {
262
+ /* istanbul ignore next */
263
+ if (!this.modal.isDialogOpen()) {
264
+ this.restartTimeout();
265
+ }
266
+ }, 61000);
267
+
268
+ window.onkeyup = this.throttle(() => {
269
+ /* istanbul ignore next */
270
+ if (!this.modal.isDialogOpen()) {
271
+ this.restartTimeout();
272
+ }
273
+ }, 61000);
274
+ }
275
+
276
+ throttle(func, wait) {
277
+ let waiting = false;
278
+ return function() {
279
+ if (waiting) {
280
+ return;
281
+ }
282
+ waiting = true;
283
+ setTimeout(async () => {
284
+ func.apply(this, arguments);
285
+ waiting = false;
286
+ }, wait);
287
+ };
288
+ }
289
+ }
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <browserconfig>
3
+ <msapplication>
4
+ <tile>
5
+ <square70x70logo src="mstile-70x70.png"/>
6
+ <square150x150logo src="mstile-150x150.png"/>
7
+ <square310x310logo src="mstile-310x310.png"/>
8
+ <wide310x150logo src="mstile-310x150.png"/>
9
+ <TileColor>#902082</TileColor>
10
+ </tile>
11
+ </msapplication>
12
+ </browserconfig>
Binary file
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "Cyfrifiad2021",
3
+ "short_name": "Cyfrifiad2021",
4
+ "icons": [
5
+ {
6
+ "src": "android-chrome-192x192.png",
7
+ "sizes": "192x192",
8
+ "type": "image/png"
9
+ },
10
+ {
11
+ "src": "android-chrome-512x512.png",
12
+ "sizes": "512x512",
13
+ "type": "image/png"
14
+ }
15
+ ],
16
+ "content_security_policy": "script-src 'self' https://cdn.ons.gov.uk; object-src 'self' https://cdn.ons.gov.uk;",
17
+ "theme_color": "#902082",
18
+ "background_color": "#902082",
19
+ "display": "standalone"
20
+ }
Binary file
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24">
2
+ <path d="M13,24C6.4,24,1,18.6,1,12C1,5.4,6.4,0,13,0c3.3,0,6.5,1.4,8.8,3.8c1,1.1,1,2.8-0.1,3.9c-1.1,1-2.8,1-3.9-0.1c-1.3-1.3-3-2.1-4.8-2.1c-3.6,0-6.5,2.9-6.5,6.5c0,3.6,2.9,6.5,6.5,6.5c1.8,0,3.5-0.7,4.8-2.1c1-1.1,2.8-1.2,3.9-0.1c1.1,1,1.2,2.8,0.1,3.9C19.5,22.6,16.3,24,13,24" fill-rule="nonzero"></path>
3
+ </svg>
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "Cyfrifiad2021",
3
+ "short_name": "Cyfrifiad2021",
4
+ "icons": [
5
+ {
6
+ "src": "android-chrome-192x192.png",
7
+ "sizes": "192x192",
8
+ "type": "image/png"
9
+ },
10
+ {
11
+ "src": "android-chrome-512x512.png",
12
+ "sizes": "512x512",
13
+ "type": "image/png"
14
+ }
15
+ ],
16
+ "theme_color": "#902082",
17
+ "background_color": "#902082",
18
+ "display": "standalone"
19
+ }
Binary file
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <browserconfig>
3
+ <msapplication>
4
+ <tile>
5
+ <square70x70logo src="mstile-70x70.png"/>
6
+ <square150x150logo src="mstile-150x150.png"/>
7
+ <square310x310logo src="mstile-310x310.png"/>
8
+ <wide310x150logo src="mstile-310x150.png"/>
9
+ <TileColor>#902082</TileColor>
10
+ </tile>
11
+ </msapplication>
12
+ </browserconfig>
Binary file
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "Census2021",
3
+ "short_name": "Census2021",
4
+ "icons": [
5
+ {
6
+ "src": "android-chrome-192x192.png",
7
+ "sizes": "192x192",
8
+ "type": "image/png"
9
+ },
10
+ {
11
+ "src": "android-chrome-512x512.png",
12
+ "sizes": "512x512",
13
+ "type": "image/png"
14
+ }
15
+ ],
16
+ "content_security_policy": "script-src 'self' https://cdn.ons.gov.uk; object-src 'self' https://cdn.ons.gov.uk;",
17
+ "theme_color": "#902082",
18
+ "background_color": "#902082",
19
+ "display": "standalone"
20
+ }
Binary file
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24">
2
+ <path d="M13,24C6.4,24,1,18.6,1,12C1,5.4,6.4,0,13,0c3.3,0,6.5,1.4,8.8,3.8c1,1.1,1,2.8-0.1,3.9c-1.1,1-2.8,1-3.9-0.1c-1.3-1.3-3-2.1-4.8-2.1c-3.6,0-6.5,2.9-6.5,6.5c0,3.6,2.9,6.5,6.5,6.5c1.8,0,3.5-0.7,4.8-2.1c1-1.1,2.8-1.2,3.9-0.1c1.1,1,1.2,2.8,0.1,3.9C19.5,22.6,16.3,24,13,24" fill-rule="nonzero"></path>
3
+ </svg>