@foeewni/web-core 3.0.0-alpha.1 → 3.0.0-alpha.11

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.
@@ -0,0 +1,375 @@
1
+ /* @docs
2
+
3
+ # Scripts:Jaunty
4
+
5
+ Jauntifies a text header with the data-jaunt-factor attribute.
6
+
7
+ Usage:
8
+ ```
9
+ <h1 data-jaunt-factor="1">Jaunty Title</h1>
10
+
11
+ <h2 data-jaunt-factor="2">Very Jaunty Title</h2>
12
+ ```
13
+
14
+ Based on James South Codepen https://codepen.io/jrsouth/pen/ZEmeoJz with ideas from
15
+ https://www.bennadel.com/blog/4310-detecting-rendered-line-breaks-in-a-text-node-in-javascript.htm
16
+ */
17
+
18
+ (() => {
19
+ // Config
20
+ const ROTATION_MAX_DEGREES = 2; // Degrees. "Normal" is around 2.5
21
+ const BACKGROUND_EXTENSION = 0.5; // rem. Normal is around 1
22
+ const CORNER_JIGGLE_MAX = 1; // rem. Normal is around .2
23
+ const BREAK_RATIO = 2.5; // ratio for when the variation on the side happens
24
+ let oneRemInPx = 0;
25
+ let extension = 0;
26
+
27
+ // Constants
28
+ const JIGGLE_ALL = 0;
29
+ const JIGGLE_UP = 1;
30
+ const JIGGLE_DOWN = 2;
31
+ const JIGGLE_LEFT = 3;
32
+ const JIGGLE_RIGHT = 4;
33
+
34
+ // Helpers
35
+ const generateRandomHex = (length) => {
36
+ let result = '';
37
+ const characters = 'ABCDEF1234567890';
38
+ const charactersLength = characters.length;
39
+ for (let i = 0; i < length; i++) {
40
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
41
+ }
42
+ return result;
43
+ };
44
+
45
+ const drawPolygon = (context, points) => {
46
+ context.beginPath();
47
+ context.moveTo(points[0].x, points[0].y);
48
+ for (let i = 1; i < points.length; i++) {
49
+ context.lineTo(points[i].x, points[i].y);
50
+ }
51
+ context.lineTo(points[0].x, points[0].y);
52
+ context.fill();
53
+ context.stroke();
54
+ };
55
+
56
+ const jauntTarget = (target, action = null) => {
57
+ if (
58
+ !target.firstChild ||
59
+ target.firstChild.nodeType !== Node.TEXT_NODE
60
+ ) {
61
+ return;
62
+ }
63
+
64
+ // jauntSeed is stored on page so remains constant when resizing or hovering
65
+ const jauntSeed = target.dataset.jauntSeed ? target.dataset.jauntSeed : generateRandomHex(4 * 8);
66
+ target.dataset.jauntSeed = jauntSeed;
67
+
68
+ // Set up the parameters
69
+ const jauntFactor = parseFloat(target.dataset.jauntFactor);
70
+ extension = BACKGROUND_EXTENSION * oneRemInPx * jauntFactor;
71
+
72
+ // Figure out the bounding boxes
73
+ // Get the bounding boxes
74
+ const targetBox = target.getBoundingClientRect();
75
+ const parentBox = target.offsetParent ? target.offsetParent.getBoundingClientRect() : targetBox;
76
+
77
+ // switch(action) {
78
+ // case 'resize':
79
+ // target.dataset.points = false;
80
+ // break;
81
+ // }
82
+
83
+ // Insert the new 2D canvas element or find the existing one
84
+ if (target.dataset.backgroundCanvasId) {
85
+ document.getElementById(
86
+ target.dataset.backgroundCanvasId
87
+ ).remove();
88
+ }
89
+ const canvas = document.createElement('canvas');
90
+ // if (target.dataset.backgroundCanvasId) {
91
+ // canvas.getContext('2d')
92
+ // .clearRect(0, 0, canvas.width, canvas.height);
93
+ // } else {
94
+ // Create a unique ID to link this element with the canvas background
95
+ target.dataset.backgroundCanvasId = generateRandomHex(12);
96
+ canvas.id = target.dataset.backgroundCanvasId;
97
+ canvas.style.position = 'absolute';
98
+ canvas.style.zIndex = -1;
99
+ canvas.style.top = `${(targetBox.top - parentBox.top) - 2 * extension}px`;
100
+ canvas.style.left = `${(targetBox.left - parentBox.left) - 2 * extension}px`;
101
+ canvas.style.width = `${targetBox.width + 4 * extension}px`;
102
+ canvas.style.height = `${targetBox.height + 4 * extension}px`;
103
+ canvas.width = targetBox.width + 4 * extension;
104
+ canvas.height = targetBox.height + 4 * extension;
105
+ canvas.style.pointerEvents = 'none';
106
+ target.parentNode.insertBefore(canvas, target);
107
+ // }
108
+
109
+ // Add rotation
110
+ if (!target.dataset.jauntRotation) {
111
+ const middle = jauntSeed.length / 2 + 1;
112
+ let rotationSeed = jauntSeed.substring(1, middle);
113
+ rotationSeed = Number(`0x${rotationSeed}`);
114
+ rotationSeed /= 10 ** (`${rotationSeed}`).length;
115
+ const rotationFactor = ROTATION_MAX_DEGREES * jauntFactor
116
+ * (rotationSeed * 2 - 1); // -1 to +1
117
+ target.dataset.jauntRotation = rotationFactor;
118
+ }
119
+ target.style.transform = `rotate(${target.dataset.jauntRotation}deg)`;
120
+ canvas.style.transform = `rotate(${target.dataset.jauntRotation}deg)`;
121
+
122
+ const context = canvas.getContext('2d');
123
+
124
+ // set the background color and remove and existing background
125
+ target.style.backgroundColor = '';
126
+ target.style.borderColor = '';
127
+ target.style.transition = 'none';
128
+ context.fillStyle = getComputedStyle(target).backgroundColor;
129
+ context.strokeStyle = getComputedStyle(target).borderColor;
130
+ target.dataset.jauntBackground = context.fillStyle;
131
+ target.dataset.jauntBorder = context.strokeStyle;
132
+ target.style.backgroundColor = 'transparent';
133
+ target.style.borderColor = 'transparent';
134
+
135
+ // Collapse whitespace
136
+ target.textContent = target.textContent.replace(/\s+/g, ' ').trim();
137
+
138
+ // Get the individual lines as rendered on screen
139
+ const { textContent } = target.firstChild;
140
+ const range = document.createRange();
141
+ range.setStart(target.firstChild, 0);
142
+ range.setEnd(target.firstChild, textContent.length);
143
+
144
+ // const outerBox = range.getBoundingClientRect();
145
+ const boxes = target.dataset.jauntFull ? [targetBox] : Array.from(range.getClientRects());
146
+ const storedPoints = [];
147
+
148
+ // function to jiggle the points around using a seed
149
+ const jigglePoint = (point, seed, mod = JIGGLE_ALL) => {
150
+ // isolate a point seed from the master seed
151
+ const startPoint = seed.index * seed.pointSeedLength;
152
+ const endPointX = startPoint + (seed.pointSeedLength / 2);
153
+ const endPointY = startPoint + seed.pointSeedLength;
154
+ const middle = seed.pointSeedLength / 2 + 1;
155
+ let xRandom = seed.boxSeed.substring(startPoint, endPointX);
156
+ let yRandom = seed.boxSeed.substring(endPointX, endPointY);
157
+ // convert the hex seed to decimal
158
+ xRandom = Number(`0x${xRandom}`);
159
+ yRandom = Number(`0x${yRandom}`);
160
+ // reduce the points to 0 -> 1 random float
161
+ xRandom /= 10 ** middle;
162
+ yRandom /= 10 ** middle;
163
+ // modify the direction of jiggle based on modifications
164
+ switch (mod) {
165
+ case JIGGLE_LEFT:
166
+ xRandom *= -2;
167
+ break;
168
+ case JIGGLE_RIGHT:
169
+ xRandom *= 2;
170
+ break;
171
+ default:
172
+ // modify the corners less
173
+ xRandom -= 0.5;
174
+ break;
175
+ }
176
+ switch (mod) {
177
+ case JIGGLE_UP:
178
+ yRandom *= -2;
179
+ break;
180
+ case JIGGLE_DOWN:
181
+ yRandom *= 2;
182
+ break;
183
+ default:
184
+ // modify the corners less
185
+ yRandom -= 0.5;
186
+ break;
187
+ }
188
+ return {
189
+ x:
190
+ point.x
191
+ + xRandom
192
+ * extension / 2
193
+ * CORNER_JIGGLE_MAX
194
+ * jauntFactor,
195
+ y:
196
+ point.y
197
+ + yRandom
198
+ * extension / 2
199
+ * CORNER_JIGGLE_MAX
200
+ * jauntFactor,
201
+ };
202
+ };
203
+ boxes.forEach((lineBox, i) => {
204
+ const points = [];
205
+ // dimension constants to use for points
206
+ const lineWidth = lineBox.width + (target.dataset.jauntFull ? - extension : (4 * extension));
207
+ const lineHeight = lineBox.height + (target.dataset.jauntFull ? - extension : (4 * extension));
208
+ const left = lineBox.left - targetBox.left + (target.dataset.jauntFull ? (3 * extension) : 0);
209
+ const right = lineBox.left - targetBox.left + (target.dataset.jauntFull ? (3 * extension) : 0) + lineWidth;
210
+ const top = lineBox.top - targetBox.top + (target.dataset.jauntFull ? (2 * extension) : 0);
211
+ const bottom = lineBox.top - targetBox.top + (target.dataset.jauntFull ? (2 * extension) : 0) + lineHeight;
212
+ // number of intemidiate points vertically and horizontally
213
+ const widthPointCount = Math.ceil(lineWidth / (lineHeight * BREAK_RATIO)) - 1;
214
+ const heightPointCount = Math.ceil(lineHeight / (lineWidth * BREAK_RATIO)) - 1;
215
+ // modify the seed string for this line box and calculate the secion lengths
216
+ const boxSeed = jauntSeed.substring(i) + jauntSeed.substring(0, i);
217
+ const pointSeedLength = boxSeed.length / (widthPointCount * 2 + heightPointCount * 2 + 4);
218
+
219
+ // Top left
220
+ let index = 0;
221
+ points.push(jigglePoint({
222
+ x: left,
223
+ y: top,
224
+ }, {
225
+ index,
226
+ boxSeed,
227
+ pointSeedLength,
228
+ }));
229
+ index += 1;
230
+ // Top edge additional points
231
+ let j = 0;
232
+ while (j < widthPointCount) {
233
+ j += 1;
234
+ points.push(jigglePoint({
235
+ x: left + (j * lineWidth / (widthPointCount + 1)),
236
+ y: top,
237
+ }, {
238
+ index,
239
+ boxSeed,
240
+ pointSeedLength,
241
+ }, JIGGLE_UP));
242
+ index += 1;
243
+ }
244
+ // Top right
245
+ points.push(jigglePoint({
246
+ x: right,
247
+ y: top,
248
+ }, {
249
+ index,
250
+ boxSeed,
251
+ pointSeedLength,
252
+ }));
253
+ index += 1;
254
+ // Right edge additional points
255
+ j = 0;
256
+ while (j < heightPointCount) {
257
+ j += 1;
258
+ points.push(jigglePoint({
259
+ x: right,
260
+ y: top + (j * lineHeight / (heightPointCount + 1)),
261
+ }, {
262
+ index,
263
+ boxSeed,
264
+ pointSeedLength,
265
+ }, JIGGLE_RIGHT));
266
+ index += 1;
267
+ }
268
+ // Bottom right
269
+ points.push(jigglePoint({
270
+ x: right,
271
+ y: bottom,
272
+ }, {
273
+ index,
274
+ boxSeed,
275
+ pointSeedLength,
276
+ }));
277
+ index += 1;
278
+ // Bottom edge additional points
279
+ j = 0;
280
+ while (j < widthPointCount) {
281
+ j += 1;
282
+ points.push(jigglePoint({
283
+ x: right - (j * lineWidth / (widthPointCount + 1)),
284
+ y: bottom,
285
+ }, {
286
+ index,
287
+ boxSeed,
288
+ pointSeedLength,
289
+ }, JIGGLE_DOWN));
290
+ index += 1;
291
+ }
292
+ // Bottom left
293
+ points.push(jigglePoint({
294
+ x: left,
295
+ y: bottom,
296
+ }, {
297
+ index,
298
+ boxSeed,
299
+ pointSeedLength,
300
+ }));
301
+ index += 1;
302
+ // Right edge additional points
303
+ j = 0;
304
+ while (j < heightPointCount) {
305
+ j += 1;
306
+ points.push(jigglePoint({
307
+ x: left,
308
+ y: bottom - (j * lineHeight / (heightPointCount + 1)),
309
+ }, {
310
+ index,
311
+ boxSeed,
312
+ pointSeedLength,
313
+ }, JIGGLE_LEFT));
314
+ index += 1;
315
+ }
316
+
317
+ drawPolygon(context, points);
318
+ storedPoints.push(points);
319
+ });
320
+
321
+ target.dataset.points = JSON.stringify(storedPoints);
322
+ };
323
+
324
+ // The main event
325
+ const createBackground = (action = null) => {
326
+ oneRemInPx = parseFloat(
327
+ getComputedStyle(document.documentElement).fontSize
328
+ );
329
+
330
+ const targets = document.querySelectorAll('[data-jaunt-factor]');
331
+
332
+ // Insert some jaunt
333
+ targets.forEach((target) => {
334
+ jauntTarget(target, action);
335
+ });
336
+ };
337
+
338
+ const processEvent = (e) => {
339
+ jauntTarget(e.target, e.type);
340
+ }
341
+
342
+ const observer = new IntersectionObserver((entries) => {
343
+ entries.forEach(entry => {
344
+ jauntTarget(entry.target, 'visibility');
345
+ });
346
+ }, {
347
+ root: document.documentElement
348
+ });
349
+
350
+ const init = () => {
351
+ const targets = document.querySelectorAll('[data-jaunt-factor]');
352
+ createBackground('init');
353
+ targets.forEach((target) => {
354
+ [
355
+ 'blur',
356
+ 'change',
357
+ 'focus',
358
+ 'mouseenter',
359
+ 'mouseleave',
360
+ ].forEach((action) => {
361
+ target.removeEventListener(action, processEvent);
362
+ target.addEventListener(action, processEvent);
363
+ });
364
+ observer.observe(target);
365
+ });
366
+ };
367
+
368
+ // Go time
369
+ document.addEventListener('DOMContentLoaded', init);
370
+ document.addEventListener('load', init);
371
+ window.addEventListener('resize', () => {
372
+ createBackground('resize');
373
+ });
374
+ window.runJaunt = init;
375
+ })();
@@ -19,21 +19,18 @@ The Friends of the Earth blockquotes use the secondary font
19
19
  @import '../../utils/scss/loader';
20
20
 
21
21
  blockquote {
22
- border-color: $gray-400;
23
- border-style: double;
24
- border-width: .2em 0;
25
- padding: $spacer*1.5 0;
22
+ padding: $spacer * 1.5 0;
26
23
  width: 80%;
27
- margin: $spacer*2 auto;
24
+ margin: ($spacer * 2) auto;
28
25
  float: none;
29
26
  clear: both;
30
27
 
31
28
  p {
32
29
  font-family: $font-family-serif;
33
- font-weight: 700;
30
+ font-weight: normal;
34
31
  font-size: $blockquote-font-size;
35
32
  line-height: $blockquote-font-size * 1.35;
36
- color: $foe-primary;
33
+ color: $foe-extradark;
37
34
 
38
35
  @include media-breakpoint-down(sm) {
39
36
  font-size: strip-units($blockquote-font-size) * $font-size-sm;
@@ -54,8 +51,6 @@ blockquote {
54
51
  }
55
52
 
56
53
  @include media-breakpoint-up(sm) {
57
- width: calc(100% * 4 / 6);
58
-
59
54
  // NOTE: The width, margin-left, and margin-right values below are
60
55
  // over-ridden for sanity within CKEditor contexts.
61
56
  &.left {
@@ -63,6 +58,7 @@ blockquote {
63
58
  clear: left;
64
59
  margin-left: calc(-100% / 6);
65
60
  margin-right: 2em;
61
+ width: calc(100% * 4 / 6);
66
62
  }
67
63
 
68
64
  &.right {
@@ -70,29 +66,27 @@ blockquote {
70
66
  clear: right;
71
67
  margin-left: 2em;
72
68
  margin-right: calc(-100% / 6);
69
+ width: calc(100% * 4 / 6);
73
70
  }
74
71
  }
75
72
 
76
73
  cite,
77
74
  & + .citation {
78
- font-family: $font-family-sans-serif;
79
- font-size: 1rem;
80
- line-height: 1.3rem;
81
- font-weight: 400;
82
- font-style: italic;
83
- color: $gray-500;
75
+ width: 80%;
76
+ margin: auto;
77
+ font-family: $font-family-serif;
78
+ font-size: $blockquote-font-size;
79
+ line-height: $spacer * 2;
80
+ font-weight: bold;
81
+ color: $foe-extradark;
84
82
  display: block;
85
- text-align: right;
86
- margin-top: 1em;
87
- padding-left: 10%;
88
-
89
- &::before {
90
- content: "\2014\00A0\00A0";
91
- color: $foe-primary;
92
- }
83
+ text-align: left;
84
+ margin-top: $spacer;
93
85
  }
94
86
 
95
87
  & + .citation {
96
- margin-top: $spacer * -1;
88
+ margin-top: $spacer * -2.5;
89
+ margin-bottom: $spacer * 2;
90
+ text-align: center;
97
91
  }
98
92
  }
@@ -20,8 +20,8 @@ Our type system is comprised of two fonts:
20
20
  To use them on your CSS please import the webfonts through Google Fonts
21
21
 
22
22
  ```
23
- @import url('https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital@0;1&family=Libre+Franklin:ital,wght@0,400;0,700;1,400;1,700&display=swap');
23
+ @import url('https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital@0;1&family=Libre+Franklin:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&display=swap');
24
24
  ```
25
25
 
26
26
  */
27
- @import url('https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital@0;1&family=Libre+Franklin:ital,wght@0,400;0,700;1,400;1,700&display=swap');
27
+ @import url('https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital@0;1&family=Libre+Franklin:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&display=swap');
package/src/fonts.js CHANGED
@@ -32,6 +32,7 @@ To use them on your CSS please import the webfonts through Google Fonts
32
32
  // Note, single line deep imports are needed here, for some reason fontawesome messes up
33
33
  // with normal imports and webpack ends up bundling the whole library (1.25mb!)
34
34
  import { library, dom } from '@fortawesome/fontawesome-svg-core';
35
+
35
36
  import { faEnvelope } from '@fortawesome/free-solid-svg-icons/faEnvelope';
36
37
  import { faSearch } from '@fortawesome/free-solid-svg-icons/faSearch';
37
38
  import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes';
@@ -40,19 +41,6 @@ import { faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons/faExt
40
41
  import { faArrowAltCircleUp } from '@fortawesome/free-solid-svg-icons/faArrowAltCircleUp';
41
42
  import { faShare } from '@fortawesome/free-solid-svg-icons/faShare';
42
43
  import { faLink } from '@fortawesome/free-solid-svg-icons/faLink';
43
- import { faTwitter } from '@fortawesome/free-brands-svg-icons/faTwitter';
44
- import { faFacebook } from '@fortawesome/free-brands-svg-icons/faFacebook';
45
- import { faFacebookF } from '@fortawesome/free-brands-svg-icons/faFacebookF';
46
- import { faPinterest } from '@fortawesome/free-brands-svg-icons/faPinterest';
47
- import { faLinkedin } from '@fortawesome/free-brands-svg-icons/faLinkedin';
48
- import { faInstagram } from '@fortawesome/free-brands-svg-icons/faInstagram';
49
- import { faYoutube } from '@fortawesome/free-brands-svg-icons/faYoutube';
50
- import { faTumblr } from '@fortawesome/free-brands-svg-icons/faTumblr';
51
- import { faWhatsapp } from '@fortawesome/free-brands-svg-icons/faWhatsapp';
52
- import { faFacebookMessenger } from '@fortawesome/free-brands-svg-icons/faFacebookMessenger';
53
- import { faTelegram } from '@fortawesome/free-brands-svg-icons/faTelegram';
54
- import { faTelegramPlane } from '@fortawesome/free-brands-svg-icons/faTelegramPlane';
55
- import { faTiktok } from '@fortawesome/free-brands-svg-icons/faTiktok';
56
44
  import { faChevronDown } from '@fortawesome/free-solid-svg-icons/faChevronDown';
57
45
  import { faChevronUp } from '@fortawesome/free-solid-svg-icons/faChevronUp';
58
46
  import { faAngleDown } from '@fortawesome/free-solid-svg-icons/faAngleDown';
@@ -76,6 +64,23 @@ import { faSave } from '@fortawesome/free-solid-svg-icons/faSave';
76
64
  import { faSignInAlt } from '@fortawesome/free-solid-svg-icons/faSignInAlt';
77
65
  import { faTrashAlt } from '@fortawesome/free-solid-svg-icons/faTrashAlt';
78
66
 
67
+ import { faTwitter } from '@fortawesome/free-brands-svg-icons/faTwitter';
68
+ import { faXTwitter } from '@fortawesome/free-brands-svg-icons/faXTwitter';
69
+ import { faFacebook } from '@fortawesome/free-brands-svg-icons/faFacebook';
70
+ import { faFacebookF } from '@fortawesome/free-brands-svg-icons/faFacebookF';
71
+ import { faPinterest } from '@fortawesome/free-brands-svg-icons/faPinterest';
72
+ import { faLinkedin } from '@fortawesome/free-brands-svg-icons/faLinkedin';
73
+ import { faInstagram } from '@fortawesome/free-brands-svg-icons/faInstagram';
74
+ import { faYoutube } from '@fortawesome/free-brands-svg-icons/faYoutube';
75
+ import { faTumblr } from '@fortawesome/free-brands-svg-icons/faTumblr';
76
+ import { faWhatsapp } from '@fortawesome/free-brands-svg-icons/faWhatsapp';
77
+ import { faFacebookMessenger } from '@fortawesome/free-brands-svg-icons/faFacebookMessenger';
78
+ import { faTelegram } from '@fortawesome/free-brands-svg-icons/faTelegram';
79
+ import { faTelegramPlane } from '@fortawesome/free-brands-svg-icons/faTelegramPlane';
80
+ import { faTiktok } from '@fortawesome/free-brands-svg-icons/faTiktok';
81
+ import { faBluesky } from '@fortawesome/free-brands-svg-icons/faBluesky';
82
+ import { faThreads } from '@fortawesome/free-brands-svg-icons/faThreads';
83
+
79
84
 
80
85
  // Add actually used FA icons
81
86
  library.add(
@@ -88,6 +93,7 @@ library.add(
88
93
  faShare,
89
94
  faLink,
90
95
  faTwitter,
96
+ faXTwitter,
91
97
  faFacebook,
92
98
  faFacebookF,
93
99
  faPinterest,
@@ -121,20 +127,25 @@ library.add(
121
127
  faSave,
122
128
  faTrashAlt,
123
129
  faCloudUploadAlt,
124
- faSignInAlt
130
+ faSignInAlt,
131
+ faBluesky,
132
+ faThreads
125
133
  );
126
134
 
127
135
  // Look for Google fonts and append them if they are not there already
128
136
  // We avoiding using @import url(); because the new URL has semicolons on it
129
137
  // and it tremendously gets broken from some preprocessors.
130
138
 
131
- const fonts = window.document.createElement('link');
132
139
  // eslint-disable-next-line max-len
133
- const href = 'https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital@0;1&family=Libre+Franklin:ital,wght@0,400;0,700;1,400;1,700&display=swap';
134
- fonts.setAttribute('rel', 'stylesheet');
135
- fonts.setAttribute('crossorigin', 'anonymous');
136
- fonts.setAttribute('href', href);
137
- document.head.appendChild(fonts);
140
+ const googleFontsHref = 'https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital@0;1&family=Libre+Franklin:ital,wght@0,400;0,700;1,400;1,700&display=swap';
141
+ const googleFontsLink = window.document.querySelector(`link[href="${googleFontsHref}"]`);
142
+ if (!googleFontsLink) {
143
+ const fonts = window.document.createElement('link');
144
+ fonts.setAttribute('rel', 'stylesheet');
145
+ fonts.setAttribute('crossorigin', 'anonymous');
146
+ fonts.setAttribute('href', googleFontsHref);
147
+ document.head.appendChild(fonts);
148
+ }
138
149
 
139
150
  // Kicks off the process of finding <i> tags and replacing with <svg>
140
151
  dom.watch();
package/src/main.js CHANGED
@@ -19,6 +19,7 @@ import './components/tools/data-click-track';
19
19
  import './components/tools/rubik-tracking';
20
20
  import './components/tools/data-defer-src';
21
21
  import './components/tools/stickystack';
22
+ import './components/tools/jaunty';
22
23
 
23
24
  // Bootstrap helpers
24
25
  import './components/layout/alerts.scss';
@@ -31,12 +31,13 @@
31
31
 
32
32
  // Applies colours to <p> and <a> elements
33
33
  @mixin text_colours ($main, $link) {
34
- p,
35
- li {
34
+ label,
35
+ li,
36
+ p {
36
37
  color: $main;
37
38
  }
38
39
 
39
- a:not(.foe-cta) {
40
+ a:not(.foe-cta):not(.btn) {
40
41
  color: $link;
41
42
 
42
43
  &:hover {