@appartmint/mint 0.12.17 → 0.12.28
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/css/mint.css +31 -7
- package/dist/css/mint.css.map +1 -1
- package/dist/css/mint.min.css +1 -1
- package/dist/css/mint.min.css.map +1 -1
- package/dist/js/imports/components/header.d.ts +4 -0
- package/dist/js/imports/components/header.d.ts.map +1 -1
- package/dist/js/imports/util/object.d.ts.map +1 -1
- package/dist/js/index.js +22 -19
- package/dist/js/index.js.map +1 -1
- package/dist/js/index.min.js +1 -1
- package/dist/js/index.min.js.map +1 -1
- package/dist/js/util.js +2 -2
- package/dist/js/util.js.map +1 -1
- package/dist/js/util.min.js +1 -1
- package/dist/js/util.min.js.map +1 -1
- package/package.json +18 -13
- package/src/scss/imports/components/_header.scss +31 -6
- package/src/scss/imports/global/_global.scss +2 -2
- package/src/scss/imports/global/_texture.scss +1 -0
- package/src/scss/imports/util/_vars.scss +5 -0
- package/src/ts/imports/components/header.ts +378 -0
- package/src/ts/imports/enum.ts +9 -0
- package/src/ts/imports/models/color.ts +96 -0
- package/src/ts/imports/models/item.ts +66 -0
- package/src/ts/imports/util/display.ts +7 -0
- package/src/ts/imports/util/event.ts +7 -0
- package/src/ts/imports/util/icon.ts +67 -0
- package/src/ts/imports/util/list.ts +19 -0
- package/src/ts/imports/util/math.ts +17 -0
- package/src/ts/imports/util/object.ts +141 -0
- package/src/ts/imports/util/selectors.ts +230 -0
- package/src/ts/imports/util/settings.ts +120 -0
- package/src/ts/imports/util/text.ts +47 -0
- package/src/ts/imports/util/window.ts +7 -0
- package/src/ts/index.ts +33 -0
- package/src/ts/util.ts +209 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Imports
|
|
3
|
+
*/
|
|
4
|
+
import { mintSide } from '../enum';
|
|
5
|
+
import mintUtil from '../../util';
|
|
6
|
+
import mintSelectors from '../util/selectors';
|
|
7
|
+
import mintSettings from '../util/settings';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Main header functionality
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export class mintHeader {
|
|
14
|
+
/**
|
|
15
|
+
* Last-logged window width
|
|
16
|
+
*/
|
|
17
|
+
lastWidth: number = mintUtil.windowWidth();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Frequently-referenced elements
|
|
21
|
+
*/
|
|
22
|
+
el: {[key: string]: HTMLElement | null} = {};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Initializes and closes the menu
|
|
26
|
+
*/
|
|
27
|
+
constructor (settings?: {[key: string]: any}) {
|
|
28
|
+
let defaultSettings: {[key: string]: any} = {
|
|
29
|
+
from: mintSide.Top,
|
|
30
|
+
fixed: true
|
|
31
|
+
};
|
|
32
|
+
mintSettings.set({ ...defaultSettings, ...settings });
|
|
33
|
+
|
|
34
|
+
this.attachElements();
|
|
35
|
+
this.attachEvents();
|
|
36
|
+
this.addClasses();
|
|
37
|
+
|
|
38
|
+
this.setMobileMenu();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Adds elements to {@link el | `this.el`}
|
|
43
|
+
*/
|
|
44
|
+
attachElements () : void {
|
|
45
|
+
this.el.html = document.querySelector('html');
|
|
46
|
+
this.el.body = document.querySelector('body');
|
|
47
|
+
this.el.header = document.getElementById(mintSelectors.getId('header'));
|
|
48
|
+
this.el.mobileButton = this.el.header?.querySelector(mintSelectors.controls(mintSelectors.getId('wrapper'))) || null;
|
|
49
|
+
this.el.wrapper = document.getElementById(mintSelectors.getId('wrapper'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Adds events to the dom
|
|
54
|
+
*/
|
|
55
|
+
attachEvents () : void {
|
|
56
|
+
//window.addEventListener('resize', mintUtil.throttleEvent(this.eHandleResize.bind(this), mintSettings.delay.default, { trailing: false }));
|
|
57
|
+
window.addEventListener('scroll', mintUtil.throttleEvent(this.eHandleScroll.bind(this), mintSettings.delay.default, { trailing: false }));
|
|
58
|
+
|
|
59
|
+
let focusables: NodeListOf<HTMLElement> | undefined = this.el.header?.querySelectorAll(mintSelectors.focusable),
|
|
60
|
+
lastFocusable: HTMLElement | undefined = focusables?.[focusables?.length - 1];
|
|
61
|
+
lastFocusable?.addEventListener('keydown', mintUtil.throttleEvent(this.eWrapTab.bind(this)));
|
|
62
|
+
focusables?.forEach((focusable: HTMLElement) => {
|
|
63
|
+
focusable.addEventListener('keydown', mintUtil.throttleEvent(this.eHandleKeypress.bind(this)));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
let menuButtons: NodeListOf<HTMLElement> | undefined = this.el.header?.querySelectorAll(mintSelectors.controls() + mintSelectors.neg(mintSelectors.controls(mintSelectors.ids.wrapper as string)));
|
|
67
|
+
menuButtons?.forEach((menuButton: HTMLElement) => {
|
|
68
|
+
menuButton.addEventListener('click', mintUtil.throttleEvent(this.eToggleMenu.bind(this), mintSettings.delay.slow, { trailing: false }));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
this.el.mobileButton?.addEventListener('click', mintUtil.throttleEvent(this.eToggleMobileMenu.bind(this), mintSettings.delay.slow, { trailing: false }));
|
|
72
|
+
this.el.wrapper?.addEventListener('transitionend', this.eTransitionEnd.bind(this));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Adds classes that inform the styles
|
|
77
|
+
*/
|
|
78
|
+
addClasses () : void {
|
|
79
|
+
if (mintSettings.fixed) {
|
|
80
|
+
this.el.body?.classList.add(mintSelectors.getClass('fixed'));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Sets the state of the mobile menu
|
|
86
|
+
* @param open - `true` to open the menu or `false` to close it
|
|
87
|
+
*/
|
|
88
|
+
setMobileMenu (open: boolean = false) : void {
|
|
89
|
+
let ariaExpanded: string = open ? 'true' : 'false',
|
|
90
|
+
ariaLabel: string = open ? 'close menu' : 'open menu';
|
|
91
|
+
|
|
92
|
+
this.el.mobileButton?.setAttribute('aria-expanded', ariaExpanded);
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
this.el.mobileButton?.setAttribute('aria-label', ariaLabel);
|
|
95
|
+
}, mintSettings.delay.fast);
|
|
96
|
+
|
|
97
|
+
if (open) {
|
|
98
|
+
if (mintSettings.fixed !== true) {
|
|
99
|
+
window.scroll({
|
|
100
|
+
top: 0,
|
|
101
|
+
left: 0,
|
|
102
|
+
behavior: 'smooth'
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
if (this.el.html) {
|
|
108
|
+
this.el.html.style.overflow = 'hidden';
|
|
109
|
+
}
|
|
110
|
+
}, mintSettings.from === mintSide.Left ? mintSettings.delay.default : mintSettings.delay.instant);
|
|
111
|
+
|
|
112
|
+
if (this.el.wrapper) {
|
|
113
|
+
this.el.wrapper.style.display = 'flex';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
requestAnimationFrame(() => {
|
|
117
|
+
this.el.wrapper?.classList.add(mintSelectors.getClass('open'));
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
if (this.el.html) {
|
|
121
|
+
this.el.html.style.overflow = 'auto';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
requestAnimationFrame(() => {
|
|
125
|
+
this.el.wrapper?.classList.remove(mintSelectors.getClass('open'));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
this.closeAllMenus();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Toggles the state of the mobile menu
|
|
134
|
+
*/
|
|
135
|
+
toggleMobileMenu () : void {
|
|
136
|
+
this.setMobileMenu(this.el.mobileButton?.getAttribute('aria-expanded')?.toLowerCase() === 'false');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Sets the state of the provided button's menu
|
|
141
|
+
* @param button - Button element to set
|
|
142
|
+
* @param open - `true` to open the menu or `false` to close it
|
|
143
|
+
*/
|
|
144
|
+
setMenu (button?: HTMLElement | null,
|
|
145
|
+
open: boolean = false) : void {
|
|
146
|
+
let ariaExpanded: string = open ? 'true' : 'false',
|
|
147
|
+
menu: HTMLElement | null = button?.nextElementSibling as HTMLElement | null;
|
|
148
|
+
if (button && menu) {
|
|
149
|
+
button.setAttribute('aria-expanded', ariaExpanded);
|
|
150
|
+
if (open) {
|
|
151
|
+
mintUtil.show(menu);
|
|
152
|
+
} else {
|
|
153
|
+
mintUtil.hide(menu);
|
|
154
|
+
this.closeSubMenus(button);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Toggles the state of the provided button's menu
|
|
161
|
+
* @param button - Button element to toggle
|
|
162
|
+
*/
|
|
163
|
+
toggleMenu (button?: HTMLElement | null) : void {
|
|
164
|
+
this.setMenu(button, button?.getAttribute('aria-expanded')?.toLowerCase() !== 'true');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Closes all submenus of the provided button's menu
|
|
169
|
+
* @param button - Button element of the parent menu
|
|
170
|
+
*/
|
|
171
|
+
closeSubMenus (button?: HTMLElement | null) : void {
|
|
172
|
+
let menu: HTMLElement | null | undefined = button?.nextElementSibling as HTMLElement,
|
|
173
|
+
subMenus: NodeListOf<HTMLElement> = menu?.querySelectorAll(mintSelectors.subMenuButtons) as NodeListOf<HTMLElement>;
|
|
174
|
+
subMenus.forEach((child: HTMLElement) => {
|
|
175
|
+
// setMenu calls this function, so ignore subsub menus
|
|
176
|
+
if (child.parentElement?.parentElement === menu) {
|
|
177
|
+
this.setMenu(child);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Closes all sibling menus of the provided button's menu
|
|
184
|
+
* @param button - Button element of the sibling menus
|
|
185
|
+
*/
|
|
186
|
+
closeSiblingMenus (button?: HTMLElement | null) : void {
|
|
187
|
+
let menu: HTMLElement | null | undefined = button?.parentElement as HTMLElement,
|
|
188
|
+
siblingMenus: NodeListOf<HTMLElement> = menu?.parentElement?.querySelectorAll(mintSelectors.subMenuButtons) as NodeListOf<HTMLElement>;
|
|
189
|
+
siblingMenus.forEach((child: HTMLElement) => {
|
|
190
|
+
if (child !== button) {
|
|
191
|
+
this.setMenu(child);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Closes all submenus of the n4vbar
|
|
198
|
+
*/
|
|
199
|
+
closeAllMenus () : void {
|
|
200
|
+
let menuButtons: NodeListOf<HTMLElement> | undefined = this.el.wrapper?.querySelectorAll(mintSelectors.subMenuButtons);
|
|
201
|
+
menuButtons?.forEach((menuButton: HTMLElement) => {
|
|
202
|
+
this.setMenu(menuButton);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Opens the menu closest to the document's focus
|
|
208
|
+
*/
|
|
209
|
+
openClosestMenu () : void {
|
|
210
|
+
let activeButton: HTMLElement | null = document.activeElement as HTMLElement | null,
|
|
211
|
+
activeMenu: HTMLElement | null = activeButton?.nextElementSibling as HTMLElement | null,
|
|
212
|
+
showing: boolean = activeButton?.getAttribute('aria-expanded')?.toLowerCase() === 'true';
|
|
213
|
+
if (activeButton?.getAttribute('aria-controls') === mintSelectors.ids.wrapper) {
|
|
214
|
+
activeMenu = this.el.wrapper;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (activeButton?.getAttribute('aria-controls') && activeMenu && !showing) {
|
|
218
|
+
activeButton.click();
|
|
219
|
+
let firstFocusable: HTMLElement | null = activeMenu.querySelector(mintSelectors.focusable);
|
|
220
|
+
firstFocusable?.focus();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Closes the menu closest to the document's focus
|
|
226
|
+
*/
|
|
227
|
+
closeClosestMenu () : void {
|
|
228
|
+
let activeElement: HTMLElement | null = document.activeElement as HTMLElement | null,
|
|
229
|
+
activeMenu: HTMLElement | null = activeElement?.closest(mintSelectors.subMenu) as HTMLElement | null,
|
|
230
|
+
activeButton: HTMLElement | null = activeMenu?.previousElementSibling ? activeMenu.previousElementSibling as HTMLElement : this.el.mobileButton;
|
|
231
|
+
if (activeElement?.getAttribute('aria-controls') && activeElement?.getAttribute('aria-expanded')?.toLowerCase() === 'true') {
|
|
232
|
+
activeButton = activeElement;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (activeButton?.getAttribute('aria-expanded')?.toLowerCase() === 'true') {
|
|
236
|
+
activeButton?.click();
|
|
237
|
+
activeButton?.focus();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Toggles the menu closest to the document's focus
|
|
243
|
+
*/
|
|
244
|
+
toggleClosestMenu () : void {
|
|
245
|
+
if (document.activeElement?.getAttribute('aria-expanded')?.toLowerCase() === 'true') {
|
|
246
|
+
this.closeClosestMenu();
|
|
247
|
+
} else {
|
|
248
|
+
this.openClosestMenu();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Closes the mobile menu when the window resizes
|
|
254
|
+
*/
|
|
255
|
+
eHandleResize (e: Event) : void {
|
|
256
|
+
// Also check if resized from mobile to desktop
|
|
257
|
+
if (mintUtil.windowWidth() !== this.lastWidth) {
|
|
258
|
+
this.setMobileMenu();
|
|
259
|
+
}
|
|
260
|
+
this.lastWidth = mintUtil.windowWidth();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Closes all submenus when the page is scrolled
|
|
265
|
+
*/
|
|
266
|
+
eHandleScroll () : void {
|
|
267
|
+
this.closeAllMenus();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Sends the focus to the menu button after tabbing past the last menu item
|
|
272
|
+
* @param e - Keyboard event
|
|
273
|
+
*/
|
|
274
|
+
eWrapTab (e: KeyboardEvent) : void {
|
|
275
|
+
if (e.key.toLowerCase() === 'tab' && !e.shiftKey) {
|
|
276
|
+
this.el.mobileButton?.focus();
|
|
277
|
+
if (document.activeElement === this.el.mobileButton) {
|
|
278
|
+
e.preventDefault();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Handles keypresses on n4vbar buttons
|
|
285
|
+
* @param e - Keyboard event
|
|
286
|
+
*/
|
|
287
|
+
eHandleButtonKeypress (e: KeyboardEvent) : void {
|
|
288
|
+
let target = e.target as HTMLElement | null,
|
|
289
|
+
subMenu = target?.closest('li');
|
|
290
|
+
switch (e.key.toLowerCase()) {
|
|
291
|
+
case 'escape':
|
|
292
|
+
if (subMenu?.classList.contains(mintSelectors.classes.open as string)) {
|
|
293
|
+
this.setMenu(subMenu);
|
|
294
|
+
} else {
|
|
295
|
+
this.setMobileMenu();
|
|
296
|
+
this.el.menuButton?.focus();
|
|
297
|
+
}
|
|
298
|
+
break;
|
|
299
|
+
case 'arrowleft':
|
|
300
|
+
this.closeClosestMenu();
|
|
301
|
+
break;
|
|
302
|
+
case 'arrowright':
|
|
303
|
+
this.openClosestMenu();
|
|
304
|
+
break;
|
|
305
|
+
case 'enter':
|
|
306
|
+
case 'space':
|
|
307
|
+
target?.click();
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Handles keypresses on n4vbar links
|
|
314
|
+
* @param e - Keyboard event
|
|
315
|
+
*/
|
|
316
|
+
eHandleLinkKeypress (e: KeyboardEvent) : void {
|
|
317
|
+
let target = e.target as HTMLElement | null;
|
|
318
|
+
switch (e.key.toLowerCase()) {
|
|
319
|
+
case 'escape':
|
|
320
|
+
case 'arrowleft':
|
|
321
|
+
this.closeClosestMenu();
|
|
322
|
+
break;
|
|
323
|
+
case 'arrowright':
|
|
324
|
+
this.openClosestMenu();
|
|
325
|
+
break;
|
|
326
|
+
case 'enter':
|
|
327
|
+
case 'space':
|
|
328
|
+
target?.click();
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Handles keypresses on the n4vbar
|
|
335
|
+
* @param e - Keyboard event
|
|
336
|
+
*/
|
|
337
|
+
eHandleKeypress (e: KeyboardEvent) : void {
|
|
338
|
+
if (e.key.toLowerCase() !== 'tab') {
|
|
339
|
+
e.preventDefault();
|
|
340
|
+
}
|
|
341
|
+
const target = e.target as HTMLElement | null;
|
|
342
|
+
switch (target?.tagName.toLowerCase()) {
|
|
343
|
+
case 'a':
|
|
344
|
+
this.eHandleLinkKeypress(e);
|
|
345
|
+
break;
|
|
346
|
+
case 'button':
|
|
347
|
+
this.eHandleButtonKeypress(e);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Toggles the mobile menu
|
|
354
|
+
*/
|
|
355
|
+
eToggleMobileMenu () : void {
|
|
356
|
+
this.toggleMobileMenu();
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Toggles the clicked submenu
|
|
361
|
+
* @param e - Mouse event
|
|
362
|
+
*/
|
|
363
|
+
eToggleMenu (e: MouseEvent) : void {
|
|
364
|
+
let target = e.target as HTMLElement | null;
|
|
365
|
+
this.closeSiblingMenus(target);
|
|
366
|
+
this.toggleMenu(target);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Runs after the mobile menu transitions
|
|
371
|
+
*/
|
|
372
|
+
eTransitionEnd () : void {
|
|
373
|
+
if (this.el.wrapper?.classList.contains(mintSelectors.getClass('open')) === false ) {
|
|
374
|
+
this.el.wrapper.style.display = 'none';
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
export default mintHeader;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color
|
|
3
|
+
*/
|
|
4
|
+
export class mintColor {
|
|
5
|
+
protected static hexBase: number = 16;
|
|
6
|
+
protected static hexMax: string = 'FF';
|
|
7
|
+
public r: number;
|
|
8
|
+
public g: number;
|
|
9
|
+
public b: number;
|
|
10
|
+
public a: number;
|
|
11
|
+
|
|
12
|
+
constructor (args: {[key: string]: number | string}) {
|
|
13
|
+
this.r = typeof args.r === 'number' ? Math.max(Math.min(args.r, mintColor.hexBase ** 2 - 1), 0) : 0;
|
|
14
|
+
this.g = typeof args.g === 'number' ? Math.max(Math.min(args.g, mintColor.hexBase ** 2 - 1), 0) : 0;
|
|
15
|
+
this.b = typeof args.b === 'number' ? Math.max(Math.min(args.b, mintColor.hexBase ** 2 - 1), 0) : 0;
|
|
16
|
+
this.a = typeof args.a === 'number' ? Math.max(Math.min(args.a, 1), 0) : 1;
|
|
17
|
+
if (typeof args.color === 'string') {
|
|
18
|
+
this.stringConstructor(args.color);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Constructor from a string argument
|
|
24
|
+
*/
|
|
25
|
+
protected stringConstructor (str: string) : void {
|
|
26
|
+
if (str.startsWith('#')) {
|
|
27
|
+
this.hexConstructor(str);
|
|
28
|
+
} else {
|
|
29
|
+
if (~str.indexOf('linear-gradient')) {
|
|
30
|
+
str = str.substring(str.indexOf('linear-gradient'), str.length);
|
|
31
|
+
}
|
|
32
|
+
this.rgbConstructor(str);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Constructor from a hex argument
|
|
38
|
+
*/
|
|
39
|
+
protected hexConstructor (hex: string) : void {
|
|
40
|
+
switch (hex.length) {
|
|
41
|
+
case 1:
|
|
42
|
+
case 5:
|
|
43
|
+
case 6:
|
|
44
|
+
return;
|
|
45
|
+
case 2:
|
|
46
|
+
hex = '#' + hex[1] + hex[1] + hex[1] + hex[1] + hex[1] + hex[1] + mintColor.hexMax;
|
|
47
|
+
break;
|
|
48
|
+
case 3:
|
|
49
|
+
hex = '#' + hex[1] + hex[1] + hex[1] + hex[2] + hex[2] + hex[2] + mintColor.hexMax;
|
|
50
|
+
break;
|
|
51
|
+
case 4:
|
|
52
|
+
hex = '#' + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3] + mintColor.hexMax;
|
|
53
|
+
break;
|
|
54
|
+
case 7:
|
|
55
|
+
hex += mintColor.hexMax;
|
|
56
|
+
break;
|
|
57
|
+
case 8:
|
|
58
|
+
hex += hex[hex.length - 1];
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
hex = hex.substring(0, 9);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.r = parseInt(hex.substring(1, 3), mintColor.hexBase);
|
|
65
|
+
this.g = parseInt(hex.substring(3, 5), mintColor.hexBase);
|
|
66
|
+
this.b = parseInt(hex.substring(5, 7), mintColor.hexBase);
|
|
67
|
+
this.a = parseInt(hex.substring(7, 9), mintColor.hexBase) / mintColor.hexBase ** 2;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Constructor from an rgba argument
|
|
72
|
+
*/
|
|
73
|
+
protected rgbConstructor (rgb: string) : void {
|
|
74
|
+
let match: RegExpMatchArray | null = rgb.match(/rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d(?:\.\d*)?)\))?/);
|
|
75
|
+
if (match) {
|
|
76
|
+
this.r = parseInt(match[1]);
|
|
77
|
+
this.g = parseInt(match[2]);
|
|
78
|
+
this.b = parseInt(match[3]);
|
|
79
|
+
this.a = parseFloat(match[4]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Returns the perceived brightness of the color
|
|
85
|
+
*/
|
|
86
|
+
getBrightness () : number {
|
|
87
|
+
if (this.a === 0) {
|
|
88
|
+
return 262;
|
|
89
|
+
}
|
|
90
|
+
if (!isNaN(this.r) && !isNaN(this.g) && !isNaN(this.b)) {
|
|
91
|
+
return Math.round((this.r * 299 + this.g * 587 + this.b * 144) / 1000);
|
|
92
|
+
}
|
|
93
|
+
return -1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export default mintColor;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic item
|
|
3
|
+
* @note - this class must be convertable with JSON
|
|
4
|
+
* - only add strings, numbers, booleans, arrays, and objects
|
|
5
|
+
*/
|
|
6
|
+
export class mintItem {
|
|
7
|
+
/**
|
|
8
|
+
* Item settings
|
|
9
|
+
*/
|
|
10
|
+
version?: number = 0;
|
|
11
|
+
priority?: number = 0;
|
|
12
|
+
price?: number = 0;
|
|
13
|
+
level?: number = 0;
|
|
14
|
+
size?: number = 0;
|
|
15
|
+
num?: number = 0;
|
|
16
|
+
width?: number = 0;
|
|
17
|
+
height?: number = 0;
|
|
18
|
+
|
|
19
|
+
centered?: boolean = false;
|
|
20
|
+
disabled?: boolean = false;
|
|
21
|
+
private?: boolean = false;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Item properties
|
|
25
|
+
*/
|
|
26
|
+
id?: string;
|
|
27
|
+
slug?: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
title?: string;
|
|
30
|
+
subtitle?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
category?: string;
|
|
33
|
+
type?: string;
|
|
34
|
+
unit?: string;
|
|
35
|
+
logo?: mintItem;
|
|
36
|
+
icon?: string;
|
|
37
|
+
position?: string;
|
|
38
|
+
transform?: string;
|
|
39
|
+
date?: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Item links
|
|
43
|
+
*/
|
|
44
|
+
src?: string;
|
|
45
|
+
href?: string;
|
|
46
|
+
target?: string;
|
|
47
|
+
routerLink?: string[];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Item data
|
|
51
|
+
*/
|
|
52
|
+
attr?: { [key: string]: string } = {};
|
|
53
|
+
params?: { [key: string]: string } = {};
|
|
54
|
+
options?: { [key: string]: string } = {};
|
|
55
|
+
lists?: { [key: string]: string[] } = {};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Item lists
|
|
59
|
+
*/
|
|
60
|
+
paragraphs?: string[] = [];
|
|
61
|
+
classes?: string[] = [];
|
|
62
|
+
items?: mintItem[] = [];
|
|
63
|
+
images?: mintItem[] = [];
|
|
64
|
+
buttons?: mintItem[] = [];
|
|
65
|
+
};
|
|
66
|
+
export default mintItem;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Imports
|
|
3
|
+
*/
|
|
4
|
+
import mintObject from "./object";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Icon helper functions
|
|
8
|
+
*/
|
|
9
|
+
export abstract class mintIcon {
|
|
10
|
+
/**
|
|
11
|
+
* Default icons
|
|
12
|
+
*/
|
|
13
|
+
static icons: {[key: string]: string} = {
|
|
14
|
+
'a[href^="mailto:"]': 'far fa-envelope',
|
|
15
|
+
'a[href^="tel:"]': 'fas fa-phone-flip',
|
|
16
|
+
'a[href^="sms:"]': 'far fa-message',
|
|
17
|
+
'a[href^="https://maps"]': 'fas fa-map-location-dot',
|
|
18
|
+
'a[href^="http"]': 'fas fa-up-right-from-square'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Appends the given icon to the given selector if there is not already an icon appended
|
|
23
|
+
*/
|
|
24
|
+
static append (icon: string, selector: string): void {
|
|
25
|
+
let items: NodeListOf<HTMLElement> = document.querySelectorAll(selector);
|
|
26
|
+
items.forEach((item: HTMLElement) => {
|
|
27
|
+
let iconElement: HTMLElement = document.createElement('i');
|
|
28
|
+
iconElement.classList.add(...icon.split(' '));
|
|
29
|
+
if (!item.querySelector('i')) {
|
|
30
|
+
item.appendChild(iconElement);
|
|
31
|
+
}
|
|
32
|
+
if (iconElement.classList.contains('fa-up-right-from-square')) {
|
|
33
|
+
item.setAttribute('target', '_blank');
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Updates the icons
|
|
40
|
+
* @param icons - the icons to update
|
|
41
|
+
*/
|
|
42
|
+
static update (icons?: {[key: string]: string | false}): void {
|
|
43
|
+
let activeIcons: {[key: string]: string} = mintObject.removeValues({
|
|
44
|
+
...this.icons,
|
|
45
|
+
...icons
|
|
46
|
+
}, [false]);
|
|
47
|
+
|
|
48
|
+
Object.keys(activeIcons).forEach((selector: string) => {
|
|
49
|
+
this.append(activeIcons[selector], selector);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Removes the given icon from the given selector
|
|
55
|
+
* @param icon - the icon to remove
|
|
56
|
+
*/
|
|
57
|
+
static remove (icon: string, selector: string): void {
|
|
58
|
+
let items: NodeListOf<HTMLElement> = document.querySelectorAll(selector);
|
|
59
|
+
items.forEach((item: HTMLElement) => {
|
|
60
|
+
let iconElement: HTMLElement | null = item.querySelector('i');
|
|
61
|
+
if (iconElement) {
|
|
62
|
+
iconElement.remove();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
export default mintIcon;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List functions for the util library
|
|
3
|
+
*/
|
|
4
|
+
export abstract class mintList {
|
|
5
|
+
/**
|
|
6
|
+
* Returns a copy of the provided list with the items in random order
|
|
7
|
+
* @param list - the list to shuffle
|
|
8
|
+
* @returns - the shuffled list
|
|
9
|
+
*/
|
|
10
|
+
static shuffle (list: any[]): any[] {
|
|
11
|
+
let copy = [...list];
|
|
12
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
13
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
14
|
+
[copy[i], copy[j]] = [copy[j], copy[i]];
|
|
15
|
+
}
|
|
16
|
+
return copy;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export default mintList;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Math functions for the util library
|
|
3
|
+
*/
|
|
4
|
+
export abstract class mintMath {
|
|
5
|
+
/**
|
|
6
|
+
* Get a random integer between min and max
|
|
7
|
+
* @param max Maximum value to return
|
|
8
|
+
* @param min Minimum value to return (default is 0)
|
|
9
|
+
* @returns a random integer between min and max
|
|
10
|
+
*/
|
|
11
|
+
static randomInt (max: number, min: number = 0): number {
|
|
12
|
+
min = Math.ceil(min);
|
|
13
|
+
max = Math.floor(max);
|
|
14
|
+
return Math.floor(Math.random() * (max - min) + min);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export default mintMath;
|