@foeewni/web-core 3.0.0-alpha.2 → 3.0.0-alpha.20
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/README.md +55 -1
- package/dist/css/foe.critical.min.css +9 -9
- package/dist/css/foe.extras.min.css +2 -2
- package/dist/css/foe.main.min.css +9 -9
- package/dist/js/foe.critical.min.js +1 -1
- package/dist/js/foe.extras.min.js +1 -1
- package/dist/js/foe.fonts.min.js +1 -1
- package/dist/js/foe.main.min.js +1 -1
- package/package.json +3 -4
- package/src/components/form/buttons.scss +56 -0
- package/src/components/form/inputs.scss +45 -2
- package/src/components/go-top/index.js +1 -1
- package/src/components/hero-panel/style.scss +61 -14
- package/src/components/layout/backgrounds.scss +101 -0
- package/src/components/layout/reset.scss +18 -0
- package/src/components/navigation/_header.scss +31 -9
- package/src/components/navigation/_mega-menu.scss +89 -0
- package/src/components/navigation/_nav-items.scss +130 -27
- package/src/components/navigation/_search.scss +18 -6
- package/src/components/navigation/defocus.js +30 -0
- package/src/components/navigation/index.js +1 -0
- package/src/components/tools/data-defer-src.js +2 -7
- package/src/components/tools/jaunty.js +379 -0
- package/src/components/typography/blockquotes.scss +17 -23
- package/src/components/typography/display.scss +6 -1
- package/src/components/typography/fonts.scss +2 -2
- package/src/fonts.js +31 -20
- package/src/main.js +1 -0
- package/src/utils/scss/helpers/_mixins.scss +4 -2
- package/src/utils/scss/helpers/_variables.scss +57 -28
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
padding-top: 0;
|
|
23
23
|
padding-bottom: 0;
|
|
24
24
|
float: none; // Resets bootstrap floating.
|
|
25
|
+
// #13294 Not sure why the mobile nav wasn't left aligned
|
|
26
|
+
text-align: left;
|
|
25
27
|
|
|
26
28
|
@include media-breakpoint-up(lg) {
|
|
27
29
|
float: left; // Reinstate for MD+
|
|
@@ -29,30 +31,28 @@
|
|
|
29
31
|
|
|
30
32
|
> a {
|
|
31
33
|
position: relative;
|
|
34
|
+
padding: .2rem;
|
|
32
35
|
line-height: $foe-nav-height-small;
|
|
33
|
-
font-weight:
|
|
36
|
+
font-weight: 900;
|
|
37
|
+
font-size: 1.25rem;
|
|
34
38
|
display: block;
|
|
35
39
|
color: $foe-extradark;
|
|
36
40
|
text-decoration: none;
|
|
37
|
-
box-shadow: inset 0 0 0 0 $foe-accent;
|
|
38
|
-
transition:
|
|
39
|
-
color $foe-transition-duration-base ease-in-out,
|
|
40
|
-
box-shadow $foe-transition-duration-base ease-in-out;
|
|
41
|
-
// transition: line-height $foe-transition-duration-base $foe-transition-easing, color $foe-transition-duration-base $foe-transition-easing;
|
|
42
41
|
|
|
43
42
|
@include media-breakpoint-up(lg) {
|
|
44
43
|
padding: 0 18px;
|
|
45
|
-
line-height: $foe-nav-height-large/
|
|
44
|
+
line-height: $foe-nav-height-large / 3;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
&:focus {
|
|
49
48
|
background-color: transparent;
|
|
50
|
-
|
|
49
|
+
box-shadow: 0 0 0 .125rem $foe-extradark;
|
|
50
|
+
outline: .125rem solid $foe-offwhite;
|
|
51
|
+
outline-offset: .125rem;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
&:hover {
|
|
54
55
|
color: $foe-offwhite;
|
|
55
|
-
box-shadow: inset 10rem 0 0 0 $foe-accent;
|
|
56
56
|
text-decoration: none;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -61,30 +61,135 @@
|
|
|
61
61
|
font-weight: 300;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
visibility: visible;
|
|
68
|
-
transition-delay: .2s;
|
|
69
|
-
z-index: $zindex-navbar + 20;
|
|
64
|
+
.foe-megamenu-container {
|
|
65
|
+
a:hover {
|
|
66
|
+
text-decoration: underline;
|
|
70
67
|
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
&.foe-has-megamenu {
|
|
71
|
+
&:focus-within,
|
|
72
|
+
&:hover {
|
|
73
|
+
.foe-megamenu-container {
|
|
74
|
+
opacity: 1;
|
|
75
|
+
visibility: visible;
|
|
76
|
+
transition-delay: .2s;
|
|
77
|
+
z-index: $zindex-navbar + 20;
|
|
78
|
+
}
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
> a::after {
|
|
81
|
+
opacity: 1;
|
|
82
|
+
transition-delay: .2s;
|
|
83
|
+
}
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
|
-
}
|
|
79
87
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
/* stylelint-disable no-descending-specificity */
|
|
89
|
+
> li {
|
|
90
|
+
> a {
|
|
91
|
+
background: linear-gradient(90deg, $foe-accent 0%, $foe-accent 50%, transparent 50%, transparent 100%);
|
|
92
|
+
background-size: 200% 100%;
|
|
93
|
+
background-position: 101% 50%;
|
|
94
|
+
background-repeat: no-repeat;
|
|
95
|
+
transition:
|
|
96
|
+
color $foe-transition-duration-base ease-in-out,
|
|
97
|
+
background-position $foe-transition-duration-base ease-in-out;
|
|
98
|
+
|
|
99
|
+
&:hover {
|
|
100
|
+
background-position: 0% 50%;
|
|
101
|
+
}
|
|
84
102
|
}
|
|
103
|
+
}
|
|
104
|
+
/* stylelint-enable no-descending-specificity */
|
|
105
|
+
|
|
106
|
+
&.menu-main {
|
|
107
|
+
display: block;
|
|
108
|
+
width: auto;
|
|
109
|
+
float: right;
|
|
110
|
+
padding: 0;
|
|
111
|
+
line-height: 4rem;
|
|
85
112
|
|
|
86
|
-
|
|
87
|
-
|
|
113
|
+
@include media-breakpoint-down(md) {
|
|
114
|
+
width: 100%;
|
|
115
|
+
overflow: hidden;
|
|
116
|
+
// #13294 this should be covered by the styles on web-core 3.0.0
|
|
117
|
+
transition: max-height $foe-transition-duration-base*2 $foe-transition-easing;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
li.foe-has-megamenu {
|
|
121
|
+
&:focus-within,
|
|
122
|
+
&:hover {
|
|
123
|
+
.foe-megamenu-container {
|
|
124
|
+
display: block;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
a + .open-megamenu {
|
|
128
|
+
&::after {
|
|
129
|
+
transform: rotate(45deg);
|
|
130
|
+
-webkit-transform: rotate(45deg);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
div.foe-megamenu-container {
|
|
136
|
+
&.collapsed {
|
|
137
|
+
display: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&.un-collapsed {
|
|
141
|
+
opacity: 1;
|
|
142
|
+
visibility: visible;
|
|
143
|
+
display: block;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@include media-breakpoint-down(md) {
|
|
148
|
+
a {
|
|
149
|
+
display: inline-block;
|
|
150
|
+
|
|
151
|
+
&.is-active {
|
|
152
|
+
&::after {
|
|
153
|
+
transform: rotate(45deg);
|
|
154
|
+
-webkit-transform: rotate(45deg);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
& + .open-megamenu {
|
|
159
|
+
padding: 1rem;
|
|
160
|
+
|
|
161
|
+
&::after {
|
|
162
|
+
position: relative;
|
|
163
|
+
content: '';
|
|
164
|
+
opacity: 1;
|
|
165
|
+
border: solid $foe-extradark;
|
|
166
|
+
border-width: 0 3px 3px 0;
|
|
167
|
+
display: inline-block;
|
|
168
|
+
padding: 3px;
|
|
169
|
+
transform: rotate(-45deg);
|
|
170
|
+
-webkit-transform: rotate(-45deg);
|
|
171
|
+
margin-left: .5rem;
|
|
172
|
+
left: 0;
|
|
173
|
+
bottom: .05rem;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
div.foe-megamenu-container { /* just for mobile menu */
|
|
179
|
+
position: relative;
|
|
180
|
+
background-color: transparent;
|
|
181
|
+
box-shadow: none;
|
|
182
|
+
|
|
183
|
+
li.foe-has-megamenu {
|
|
184
|
+
&:focus-within,
|
|
185
|
+
&:hover {
|
|
186
|
+
.foe-megamenu-container {
|
|
187
|
+
display: block;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
88
193
|
}
|
|
89
194
|
}
|
|
90
195
|
}
|
|
@@ -92,8 +197,6 @@
|
|
|
92
197
|
// Handheld only
|
|
93
198
|
@include media-breakpoint-down(md) {
|
|
94
199
|
&.foe-header-mobile-is-open {
|
|
95
|
-
background-color: $foe-extradark !important;
|
|
96
|
-
|
|
97
200
|
ul.navbar-nav {
|
|
98
201
|
max-height: calc(100vh - 4rem);
|
|
99
202
|
overflow-y: auto;
|
|
@@ -14,13 +14,21 @@
|
|
|
14
14
|
a.search-button {
|
|
15
15
|
text-decoration: none !important;
|
|
16
16
|
position: relative;
|
|
17
|
-
|
|
18
|
-
color: $foe-
|
|
17
|
+
height: $foe-nav-height-small;
|
|
18
|
+
color: $foe-extradark !important;
|
|
19
19
|
transition: line-height $foe-transition-duration-base $foe-transition-easing;
|
|
20
20
|
width: calc($spacer * 3);
|
|
21
21
|
padding-left: calc($grid-gutter-width / 2);
|
|
22
22
|
padding-right: calc($grid-gutter-width / 2);
|
|
23
|
-
display
|
|
23
|
+
// #13293 display switched to inline-flex for search icon alignment on mobile
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
vertical-align: middle;
|
|
27
|
+
|
|
28
|
+
.svg-inline--fa {
|
|
29
|
+
height: 1.5em;
|
|
30
|
+
transition: height $foe-transition-duration-base $foe-transition-easing;
|
|
31
|
+
}
|
|
24
32
|
|
|
25
33
|
.fa-times {
|
|
26
34
|
display: none;
|
|
@@ -35,11 +43,11 @@
|
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
@include media-breakpoint-up(md) {
|
|
38
|
-
|
|
46
|
+
height: $foe-nav-height-medium;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
@include media-breakpoint-up(lg) {
|
|
42
|
-
|
|
50
|
+
height: $foe-nav-height-large;
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
&::after {
|
|
@@ -117,8 +125,12 @@
|
|
|
117
125
|
&.js-menustack-stuck {
|
|
118
126
|
.header-search {
|
|
119
127
|
a.search-button {
|
|
128
|
+
.svg-inline--fa {
|
|
129
|
+
height: 1em;
|
|
130
|
+
}
|
|
131
|
+
|
|
120
132
|
@include media-breakpoint-up(lg) {
|
|
121
|
-
|
|
133
|
+
height: $foe-nav-height-large-scrolled;
|
|
122
134
|
}
|
|
123
135
|
}
|
|
124
136
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is introduced to overcome the :focus-within styles on the mega menu remaining open when ctrl-clicking a navigation link.
|
|
3
|
+
* The mega menu styles hold the menu open when a link is focused on so that a keyboard user can navigate through.
|
|
4
|
+
* However if you click on the link element it gains the focus state but as it's opening an external window/tab so
|
|
5
|
+
* the focus remains and mousing out of the menu doesn't close it. This snippet removes the focus state when something
|
|
6
|
+
* is clicked on wit the ctrl key on clicked on with a middle mouse button.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
(() => {
|
|
10
|
+
const DeFocus = {
|
|
11
|
+
init: () => {
|
|
12
|
+
document.addEventListener('click', (e) => {
|
|
13
|
+
// ctrl click for openning in a new tab
|
|
14
|
+
if (e.ctrlKey) {
|
|
15
|
+
DeFocus.removeFocus();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
document.addEventListener('auxclick', (e) => {
|
|
19
|
+
// middle button click
|
|
20
|
+
if (e.button === 1) {
|
|
21
|
+
DeFocus.removeFocus();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
removeFocus: () => {
|
|
26
|
+
document.querySelectorAll(':focus').forEach(element => element.blur());
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
window.addEventListener('DOMContentLoaded', DeFocus.init);
|
|
30
|
+
})();
|
|
@@ -50,20 +50,15 @@ import './data-defer-src.scss';
|
|
|
50
50
|
entries.forEach((entry) => {
|
|
51
51
|
if (!isVisible && entry.intersectionRatio > 0) {
|
|
52
52
|
isVisible = true;
|
|
53
|
-
|
|
54
|
-
el.contentWindow.location.replace(source);
|
|
55
|
-
} else {
|
|
56
|
-
el.src = source;
|
|
57
|
-
}
|
|
53
|
+
el.src = source;
|
|
58
54
|
}
|
|
59
55
|
|
|
60
56
|
if (el.hasAttribute('data-defer-dispose') && isVisible && entry.intersectionRatio === 0) {
|
|
61
57
|
isVisible = false;
|
|
62
58
|
if (el.tagName === 'IFRAME') {
|
|
63
59
|
el.contentWindow.location.replace('about:blank');
|
|
64
|
-
} else {
|
|
65
|
-
el.removeAttribute('src');
|
|
66
60
|
}
|
|
61
|
+
el.removeAttribute('src');
|
|
67
62
|
el.classList.add('js-defer-is-loading');
|
|
68
63
|
}
|
|
69
64
|
});
|
|
@@ -0,0 +1,379 @@
|
|
|
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) => {
|
|
57
|
+
if (
|
|
58
|
+
!target.firstChild
|
|
59
|
+
|| target.firstChild.nodeType !== Node.TEXT_NODE
|
|
60
|
+
|| !target.textContent.replace(/\s+/g, ' ').trim().length
|
|
61
|
+
) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// jauntSeed is stored on page so remains constant when resizing or hovering
|
|
66
|
+
const jauntSeed = target.dataset.jauntSeed ? target.dataset.jauntSeed : generateRandomHex(4 * 8);
|
|
67
|
+
target.dataset.jauntSeed = jauntSeed;
|
|
68
|
+
|
|
69
|
+
// Set up the parameters
|
|
70
|
+
const jauntFactor = parseFloat(target.dataset.jauntFactor);
|
|
71
|
+
extension = BACKGROUND_EXTENSION * oneRemInPx * jauntFactor;
|
|
72
|
+
|
|
73
|
+
// Figure out the bounding boxes
|
|
74
|
+
// Get the bounding boxes
|
|
75
|
+
if (getComputedStyle(target.parentNode).position === 'static') {
|
|
76
|
+
// static parents were resultibngin top drift on the top positioning
|
|
77
|
+
// A lot of the button elements have a parent with relative anyway
|
|
78
|
+
target.parentNode.style.position = 'relative';
|
|
79
|
+
}
|
|
80
|
+
const targetBox = target.getBoundingClientRect();
|
|
81
|
+
const parentBox = target.offsetParent ? target.offsetParent.getBoundingClientRect() : targetBox;
|
|
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
|
+
target.dataset.backgroundCanvasId = generateRandomHex(12);
|
|
91
|
+
canvas.id = target.dataset.backgroundCanvasId;
|
|
92
|
+
canvas.style.position = 'absolute';
|
|
93
|
+
canvas.style.zIndex = -1;
|
|
94
|
+
canvas.style.top = `${(targetBox.top - parentBox.top) - (2 * extension)}px`;
|
|
95
|
+
canvas.style.left = `${(targetBox.left - parentBox.left) - (2 * extension)}px`;
|
|
96
|
+
canvas.style.width = `${targetBox.width + (4 * extension)}px`;
|
|
97
|
+
canvas.style.height = `${targetBox.height + (4 * extension)}px`;
|
|
98
|
+
canvas.width = targetBox.width + (4 * extension);
|
|
99
|
+
canvas.height = targetBox.height + (4 * extension);
|
|
100
|
+
canvas.style.pointerEvents = 'none';
|
|
101
|
+
target.parentNode.insertBefore(canvas, target);
|
|
102
|
+
|
|
103
|
+
// Add rotation
|
|
104
|
+
// if (!target.dataset.jauntRotation) {
|
|
105
|
+
// const middle = jauntSeed.length / 2 + 1;
|
|
106
|
+
// let rotationSeed = jauntSeed.substring(1, middle);
|
|
107
|
+
// rotationSeed = Number(`0x${rotationSeed}`);
|
|
108
|
+
// rotationSeed /= 10 ** (`${rotationSeed}`).length;
|
|
109
|
+
// const rotationFactor = ROTATION_MAX_DEGREES * jauntFactor
|
|
110
|
+
// * (rotationSeed * 2 - 1); // -1 to +1
|
|
111
|
+
// target.dataset.jauntRotation = rotationFactor;
|
|
112
|
+
// }
|
|
113
|
+
// target.style.transform = `rotate(${target.dataset.jauntRotation}deg)`;
|
|
114
|
+
// canvas.style.transform = `rotate(${target.dataset.jauntRotation}deg)`;
|
|
115
|
+
|
|
116
|
+
const context = canvas.getContext('2d');
|
|
117
|
+
|
|
118
|
+
// set the background color and remove and existing background
|
|
119
|
+
target.style.backgroundColor = '';
|
|
120
|
+
target.style.borderColor = '';
|
|
121
|
+
target.style.transition = 'none';
|
|
122
|
+
context.fillStyle = getComputedStyle(target).backgroundColor;
|
|
123
|
+
context.strokeStyle = getComputedStyle(target).borderColor;
|
|
124
|
+
target.dataset.jauntBackground = context.fillStyle;
|
|
125
|
+
target.dataset.jauntBorder = context.strokeStyle;
|
|
126
|
+
target.style.backgroundColor = 'transparent';
|
|
127
|
+
target.style.borderColor = 'transparent';
|
|
128
|
+
|
|
129
|
+
const boxes = target.dataset.jauntFull ? [targetBox] : [];
|
|
130
|
+
if (!target.dataset.jauntFull) {
|
|
131
|
+
target.childNodes.forEach((text) => {
|
|
132
|
+
if (text.nodeType === Node.TEXT_NODE) {
|
|
133
|
+
// Collapse whitespace
|
|
134
|
+
text.textContent = text.textContent.replace(/\s+/g, ' ').trim();
|
|
135
|
+
// Get the individual lines as rendered on screen
|
|
136
|
+
const nodeRange = document.createRange();
|
|
137
|
+
nodeRange.setStart(text, 0);
|
|
138
|
+
nodeRange.setEnd(text, text.textContent.length);
|
|
139
|
+
Array.from(nodeRange.getClientRects()).forEach((rect) => {
|
|
140
|
+
boxes.push(rect);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// const outerBox = range.getBoundingClientRect();
|
|
147
|
+
const storedPoints = [];
|
|
148
|
+
|
|
149
|
+
// function to jiggle the points around using a seed
|
|
150
|
+
const jigglePoint = (point, seed, mod = JIGGLE_ALL) => {
|
|
151
|
+
// isolate a point seed from the master seed
|
|
152
|
+
const startPoint = seed.index * seed.pointSeedLength;
|
|
153
|
+
const endPointX = startPoint + (seed.pointSeedLength / 2);
|
|
154
|
+
const endPointY = startPoint + seed.pointSeedLength;
|
|
155
|
+
const middle = seed.pointSeedLength / 2 + 1;
|
|
156
|
+
let xRandom = seed.boxSeed.substring(startPoint, endPointX);
|
|
157
|
+
let yRandom = seed.boxSeed.substring(endPointX, endPointY);
|
|
158
|
+
// convert the hex seed to decimal
|
|
159
|
+
xRandom = Number(`0x${xRandom}`);
|
|
160
|
+
yRandom = Number(`0x${yRandom}`);
|
|
161
|
+
// reduce the points to 0 -> 1 random float
|
|
162
|
+
xRandom /= 10 ** middle;
|
|
163
|
+
yRandom /= 10 ** middle;
|
|
164
|
+
// modify the direction of jiggle based on modifications
|
|
165
|
+
switch (mod) {
|
|
166
|
+
case JIGGLE_LEFT:
|
|
167
|
+
xRandom *= -1;
|
|
168
|
+
break;
|
|
169
|
+
case JIGGLE_RIGHT:
|
|
170
|
+
xRandom *= 1;
|
|
171
|
+
break;
|
|
172
|
+
default:
|
|
173
|
+
// modify the corners less
|
|
174
|
+
xRandom -= 0.5;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
switch (mod) {
|
|
178
|
+
case JIGGLE_UP:
|
|
179
|
+
yRandom *= -1;
|
|
180
|
+
break;
|
|
181
|
+
case JIGGLE_DOWN:
|
|
182
|
+
yRandom *= 1;
|
|
183
|
+
break;
|
|
184
|
+
default:
|
|
185
|
+
// modify the corners less
|
|
186
|
+
yRandom -= 0.5;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
x:
|
|
191
|
+
point.x
|
|
192
|
+
+ xRandom
|
|
193
|
+
* extension / 2
|
|
194
|
+
* CORNER_JIGGLE_MAX
|
|
195
|
+
* jauntFactor,
|
|
196
|
+
y:
|
|
197
|
+
point.y
|
|
198
|
+
+ yRandom
|
|
199
|
+
* extension / 2
|
|
200
|
+
* CORNER_JIGGLE_MAX
|
|
201
|
+
* jauntFactor,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
boxes.forEach((lineBox, i) => {
|
|
205
|
+
const points = [];
|
|
206
|
+
// dimension constants to use for points
|
|
207
|
+
const lineWidth = lineBox.width + (target.dataset.jauntFull ? 0 : (4 * extension));
|
|
208
|
+
const lineHeight = lineBox.height + (target.dataset.jauntFull ? 0 : (4 * extension));
|
|
209
|
+
if (!lineWidth || !lineHeight) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const left = lineBox.left - targetBox.left + (target.dataset.jauntFull ? 2 * extension : 0);
|
|
213
|
+
const right = lineBox.left - targetBox.left + lineWidth + (target.dataset.jauntFull ? 2 * extension : 0);
|
|
214
|
+
const top = lineBox.top - targetBox.top + (target.dataset.jauntFull ? 2 * extension : 0);
|
|
215
|
+
const bottom = lineBox.top - targetBox.top + lineHeight + (target.dataset.jauntFull ? 2 * extension : 0);
|
|
216
|
+
// number of intemidiate points vertically and horizontally
|
|
217
|
+
const widthPointCount = Math.ceil(lineWidth / (lineHeight * BREAK_RATIO)) - 1;
|
|
218
|
+
const heightPointCount = Math.ceil(lineHeight / (lineWidth * BREAK_RATIO)) - 1;
|
|
219
|
+
// modify the seed string for this line box and calculate the secion lengths
|
|
220
|
+
const boxSeed = jauntSeed.substring(i) + jauntSeed.substring(0, i);
|
|
221
|
+
const pointSeedLength = boxSeed.length / (widthPointCount * 2 + heightPointCount * 2 + 4);
|
|
222
|
+
|
|
223
|
+
// Top left
|
|
224
|
+
let index = 0;
|
|
225
|
+
points.push(jigglePoint({
|
|
226
|
+
x: left,
|
|
227
|
+
y: top,
|
|
228
|
+
}, {
|
|
229
|
+
index,
|
|
230
|
+
boxSeed,
|
|
231
|
+
pointSeedLength,
|
|
232
|
+
}));
|
|
233
|
+
index += 1;
|
|
234
|
+
// Top edge additional points
|
|
235
|
+
let j = 0;
|
|
236
|
+
while (j < widthPointCount) {
|
|
237
|
+
j += 1;
|
|
238
|
+
points.push(jigglePoint({
|
|
239
|
+
x: left + (j * lineWidth / (widthPointCount + 1)),
|
|
240
|
+
y: top,
|
|
241
|
+
}, {
|
|
242
|
+
index,
|
|
243
|
+
boxSeed,
|
|
244
|
+
pointSeedLength,
|
|
245
|
+
}, JIGGLE_UP));
|
|
246
|
+
index += 1;
|
|
247
|
+
}
|
|
248
|
+
// Top right
|
|
249
|
+
points.push(jigglePoint({
|
|
250
|
+
x: right,
|
|
251
|
+
y: top,
|
|
252
|
+
}, {
|
|
253
|
+
index,
|
|
254
|
+
boxSeed,
|
|
255
|
+
pointSeedLength,
|
|
256
|
+
}));
|
|
257
|
+
index += 1;
|
|
258
|
+
// Right edge additional points
|
|
259
|
+
j = 0;
|
|
260
|
+
while (j < heightPointCount) {
|
|
261
|
+
j += 1;
|
|
262
|
+
points.push(jigglePoint({
|
|
263
|
+
x: right,
|
|
264
|
+
y: top + (j * lineHeight / (heightPointCount + 1)),
|
|
265
|
+
}, {
|
|
266
|
+
index,
|
|
267
|
+
boxSeed,
|
|
268
|
+
pointSeedLength,
|
|
269
|
+
}, JIGGLE_RIGHT));
|
|
270
|
+
index += 1;
|
|
271
|
+
}
|
|
272
|
+
// Bottom right
|
|
273
|
+
points.push(jigglePoint({
|
|
274
|
+
x: right,
|
|
275
|
+
y: bottom,
|
|
276
|
+
}, {
|
|
277
|
+
index,
|
|
278
|
+
boxSeed,
|
|
279
|
+
pointSeedLength,
|
|
280
|
+
}));
|
|
281
|
+
index += 1;
|
|
282
|
+
// Bottom edge additional points
|
|
283
|
+
j = 0;
|
|
284
|
+
while (j < widthPointCount) {
|
|
285
|
+
j += 1;
|
|
286
|
+
points.push(jigglePoint({
|
|
287
|
+
x: right - (j * lineWidth / (widthPointCount + 1)),
|
|
288
|
+
y: bottom,
|
|
289
|
+
}, {
|
|
290
|
+
index,
|
|
291
|
+
boxSeed,
|
|
292
|
+
pointSeedLength,
|
|
293
|
+
}, JIGGLE_DOWN));
|
|
294
|
+
index += 1;
|
|
295
|
+
}
|
|
296
|
+
// Bottom left
|
|
297
|
+
points.push(jigglePoint({
|
|
298
|
+
x: left,
|
|
299
|
+
y: bottom,
|
|
300
|
+
}, {
|
|
301
|
+
index,
|
|
302
|
+
boxSeed,
|
|
303
|
+
pointSeedLength,
|
|
304
|
+
}));
|
|
305
|
+
index += 1;
|
|
306
|
+
// Right edge additional points
|
|
307
|
+
j = 0;
|
|
308
|
+
while (j < heightPointCount) {
|
|
309
|
+
j += 1;
|
|
310
|
+
points.push(jigglePoint({
|
|
311
|
+
x: left,
|
|
312
|
+
y: bottom - (j * lineHeight / (heightPointCount + 1)),
|
|
313
|
+
}, {
|
|
314
|
+
index,
|
|
315
|
+
boxSeed,
|
|
316
|
+
pointSeedLength,
|
|
317
|
+
}, JIGGLE_LEFT));
|
|
318
|
+
index += 1;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
drawPolygon(context, points);
|
|
322
|
+
storedPoints.push(points);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
target.dataset.points = JSON.stringify(storedPoints);
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// The main event
|
|
329
|
+
const createBackground = (action = null, context = document) => {
|
|
330
|
+
oneRemInPx = parseFloat(
|
|
331
|
+
getComputedStyle(document.documentElement).fontSize
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
const targets = context.querySelectorAll('[data-jaunt-factor]');
|
|
335
|
+
|
|
336
|
+
// Insert some jaunt
|
|
337
|
+
targets.forEach((target) => {
|
|
338
|
+
jauntTarget(target, action);
|
|
339
|
+
});
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const processEvent = (e) => {
|
|
343
|
+
jauntTarget(e.target, e.type);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const observer = new IntersectionObserver((entries) => {
|
|
347
|
+
entries.forEach((entry) => {
|
|
348
|
+
jauntTarget(entry.target, 'visibility');
|
|
349
|
+
});
|
|
350
|
+
}, {
|
|
351
|
+
root: document.documentElement,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const init = (context = document) => {
|
|
355
|
+
const targets = context.querySelectorAll('[data-jaunt-factor]');
|
|
356
|
+
createBackground('init', context);
|
|
357
|
+
targets.forEach((target) => {
|
|
358
|
+
[
|
|
359
|
+
'blur',
|
|
360
|
+
'change',
|
|
361
|
+
'focus',
|
|
362
|
+
'mouseenter',
|
|
363
|
+
'mouseleave',
|
|
364
|
+
].forEach((action) => {
|
|
365
|
+
target.removeEventListener(action, processEvent);
|
|
366
|
+
target.addEventListener(action, processEvent);
|
|
367
|
+
});
|
|
368
|
+
observer.observe(target);
|
|
369
|
+
});
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// Go time
|
|
373
|
+
document.addEventListener('DOMContentLoaded', () => init());
|
|
374
|
+
document.addEventListener('load', () => init());
|
|
375
|
+
window.addEventListener('resize', () => {
|
|
376
|
+
createBackground('resize');
|
|
377
|
+
});
|
|
378
|
+
window.runJaunt = init;
|
|
379
|
+
})();
|