diff --git a/docs/assets/js/src/back-to-top-button.js b/docs/assets/js/src/back-to-top-button.js
index 1c903a385..fb65a5f28 100644
--- a/docs/assets/js/src/back-to-top-button.js
+++ b/docs/assets/js/src/back-to-top-button.js
@@ -1,64 +1,64 @@
// Add back-to-top button
// Create/style button
-const button = document.createElement('button');
-button.classList.add('back-to-top');
+const button = document.createElement('button')
+button.classList.add('back-to-top')
// Create button SVG
-const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
-svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
-svgElement.setAttribute('height', '2em');
-svgElement.setAttribute('viewBox', '0 0 448 512');
+const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
+svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
+svgElement.setAttribute('height', '2em')
+svgElement.setAttribute('viewBox', '0 0 448 512')
// Create button SVG path
-const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
-pathElement.setAttribute('d', 'M246.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L224 109.3 361.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160zm160 352l-160-160c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L224 301.3 361.4 438.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3z');
+const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path')
+pathElement.setAttribute('d', 'M246.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L224 109.3 361.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160zm160 352l-160-160c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L224 301.3 361.4 438.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3z')
// Merge elements
-svgElement.append(pathElement); button.append(svgElement);
-document.body.append(button);
+svgElement.append(pathElement) ; button.append(svgElement)
+document.body.append(button)
function fadeIn(el, duration) {
- if (el.classList.contains('done')) return;
- el.classList.add('done'); el.style.opacity = 0;
- let last = +new Date();
+ if (el.classList.contains('done')) return
+ el.classList.add('done') ; el.style.opacity = 0
+ let last = +new Date()
const tick = () => {
- el.style.opacity = +el.style.opacity + (new Date() - last) / duration;
- last = +new Date();
+ el.style.opacity = +el.style.opacity + (new Date() - last) / duration
+ last = +new Date()
if (+el.style.opacity < 1)
(window.requestAnimationFrame && requestAnimationFrame(tick)) ||
- setTimeout(tick, 16);
- else el.style.display = 'block';
- };
- tick();
+ setTimeout(tick, 16)
+ else el.style.display = 'block'
+ }
+ tick()
}
function fadeOut(el, duration) {
- if (!el.classList.contains('done')) return;
- el.classList.remove('done'); el.style.opacity = 1;
- let last = +new Date();
+ if (!el.classList.contains('done')) return
+ el.classList.remove('done') ; el.style.opacity = 1
+ let last = +new Date()
const tick = () => {
- el.style.opacity = +el.style.opacity - (new Date() - last) / duration;
- last = +new Date();
+ el.style.opacity = +el.style.opacity - (new Date() - last) / duration
+ last = +new Date()
if (+el.style.opacity > 0)
(window.requestAnimationFrame && requestAnimationFrame(tick)) ||
- setTimeout(tick, 16);
- else el.style.display = 'none';
- };
- tick();
+ setTimeout(tick, 16)
+ else el.style.display = 'none'
+ }
+ tick()
}
function scrollToTop() {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
- window.requestAnimationFrame(scrollToTop);
- window.scrollTo(0, c - c / 8);
+ window.requestAnimationFrame(scrollToTop)
+ window.scrollTo(0, c - c / 8)
}
}
-button.addEventListener('click', scrollToTop);
+button.addEventListener('click', scrollToTop)
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY || document.documentElement.scrollTop;
- if (scrollTop > 0) fadeIn(button, 500);
- else fadeOut(button, 500);
-});
\ No newline at end of file
+ if (scrollTop > 0) fadeIn(button, 500)
+ else fadeOut(button, 500)
+});
diff --git a/docs/assets/js/src/copy-code-button.js b/docs/assets/js/src/copy-code-button.js
index 51692878e..4162312c7 100644
--- a/docs/assets/js/src/copy-code-button.js
+++ b/docs/assets/js/src/copy-code-button.js
@@ -5,19 +5,19 @@
return (s =
"function" == typeof Symbol && "symbol" == typeof Symbol.iterator
? function (o) {
- return typeof o;
+ return typeof o
}
: function (o) {
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
- })(o);
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o
+ })(o)
}
!(function (o, e) {
- void 0 === e && (e = {});
- var t = e.insertAt;
+ void 0 === e && (e = {})
+ var t = e.insertAt
if (o && "undefined" != typeof document) {
var n = document.head || document.getElementsByTagName("head")[0],
c = document.createElement("style");
- (c.type = "text/css"), "top" === t && n.firstChild ? n.insertBefore(c, n.firstChild) : n.append(c), c.styleSheet ? (c.styleSheet.cssText = o) : c.append(document.createTextNode(o));
+ (c.type = "text/css"), "top" === t && n.firstChild ? n.insertBefore(c, n.firstChild) : n.append(c), c.styleSheet ? (c.styleSheet.cssText = o) : c.append(document.createTextNode(o))
}
})(
".docsify-copy-code-button,.docsify-copy-code-button span{cursor:pointer}.docsify-copy-code-button{position:absolute;z-index:1;top:0;right:0;overflow:visible;padding:.65em .8em;border:0;border-radius:0;outline:0;font-size:1em;background:grey;background:var(--theme-color,grey);color:#fff;opacity:1}.docsify-copy-code-button span{border-radius:3px;background:inherit;pointer-events:none}.docsify-copy-code-button .error,.docsify-copy-code-button .success{position:absolute;z-index:1000;top:24px;left:12px;padding:.5em .65em;font-size:.825em;opacity:0;transform:translateX(-88%)translateY(-50%)}.docsify-copy-code-button.error .error,.docsify-copy-code-button.success .success{left:12px;top:24px;opacity:1;,pre:hover .docsify-copy-code-button{opacity:1}"
@@ -27,9 +27,9 @@
init: function () {
return function (o, e) {
o.ready(function () {
- console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.");
- });
- };
+ console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")
+ })
+ }
},
}),
(window.$docsify = window.$docsify || {}),
@@ -37,28 +37,28 @@
function (o, r) {
o.doneEach(function () {
var o = Array.apply(null, document.querySelectorAll("pre[data-lang]")),
- c = { buttonText: "<> Copy code", errorText: "Error", successText: "Code copied!" };
+ c = { buttonText: "<> Copy code", errorText: "Error", successText: "Code copied!" }
r.config.copyCode &&
Object.keys(c).forEach(function (t) {
- var n = r.config.copyCode[t];
+ var n = r.config.copyCode[t]
"string" == typeof n
? (c[t] = n)
: "object" === s(n) &&
Object.keys(n).some(function (o) {
- var e = -1 < location.href.indexOf(o);
- return (c[t] = e ? n[o] : c[t]), e;
- });
- });
+ var e = -1 < location.href.indexOf(o)
+ return (c[t] = e ? n[o] : c[t]), e
+ })
+ })
var e = [
'",
- ].join("");
+ ].join("")
o.forEach(function (o) {
o.insertAdjacentHTML("beforeend", e);
- });
+ })
}),
o.mounted(function () {
document.querySelector(".content").addEventListener("click", function (o) {
@@ -66,26 +66,26 @@
var e = "BUTTON" === o.target.tagName ? o.target : o.target.parentNode,
t = document.createRange(),
n = e.parentNode.querySelector("code"),
- c = window.getSelection();
- t.selectNode(n), c.removeAllRanges(), c.addRange(t);
+ c = window.getSelection()
+ t.selectNode(n), c.removeAllRanges(), c.addRange(t)
try {
document.execCommand("copy") &&
(e.classList.add("success"), e.querySelector('.label').style.display = 'none',
setTimeout(function () {
- e.classList.remove("success");
- e.querySelector('.label').style.display = 'inline';
- }, 2000));
+ e.classList.remove("success")
+ e.querySelector('.label').style.display = 'inline';
+ }, 2000))
} catch (o) {
console.error("docsify-copy-code: ".concat(o)),
e.classList.add("error"),
setTimeout(function () {
- e.classList.remove("error");
+ e.classList.remove("error")
}, 2000);
}
- "function" == typeof (c = window.getSelection()).removeRange ? c.removeRange(t) : "function" == typeof c.removeAllRanges && c.removeAllRanges();
+ "function" == typeof (c = window.getSelection()).removeRange ? c.removeRange(t) : "function" == typeof c.removeAllRanges && c.removeAllRanges()
}
- });
- });
+ })
+ })
},
- ].concat(window.$docsify.plugins || []));
-})();
\ No newline at end of file
+ ].concat(window.$docsify.plugins || []))
+})();
diff --git a/docs/assets/js/src/onload-hacks.js b/docs/assets/js/src/onload-hacks.js
index 5aa26e53d..a45d0612f 100644
--- a/docs/assets/js/src/onload-hacks.js
+++ b/docs/assets/js/src/onload-hacks.js
@@ -1,10 +1,10 @@
/* Hack page elements on load */
-const taglineWords = []; // for iObserver's scrambleText() + randomizeCase()
+const taglineWords = [] // for iObserver's scrambleText() + randomizeCase()
const features = [ // for iObserver's typeText() to #feature-list
'>> Feature-rich', '>> Object-oriented', '>> Easy-to-use',
- '>> Lightweight (yet optimally performant)' ];
-const visibilityMap = []; // to store flags for section visibility
+ '>> Lightweight (yet optimally performant)' ]
+const visibilityMap = [] // to store flags for section visibility
const sectionColors = [ // for mdLoaded.then's scroll color hacks
'#64ffff', // Importing the Library
'#f9ee16', // Greasemonkey
@@ -12,154 +12,154 @@ const sectionColors = [ // for mdLoaded.then's scroll color hacks
'orange', // Usage
'#b981f9', // Made w/ chatgpt.js
'#f581f9', // ChatGPT Infinity tile
- '#81f9c3' ]; // Contributors
+ '#81f9c3' ] // Contributors
const iniStarZvelocity = window.starVelocity.z,
- warpDuration = 1600, hiWarpDuration = 1400, starResetDelay = 15;
+ warpDuration = 1600, hiWarpDuration = 1400, starResetDelay = 15
// Define OBSERVERS
const mdLoaded = new Promise((resolve) => {
const mdObserver = new MutationObserver((mutationsList, observer) => {
- if (document.querySelector('#shields')) { observer.disconnect(); resolve(); }});
- mdObserver.observe(document.body, { childList: true, subtree: true });
-});
+ if (document.querySelector('#shields')) { observer.disconnect() ; resolve() }})
+ mdObserver.observe(document.body, { childList: true, subtree: true })
+})
const iObserver = new IntersectionObserver(entries => { entries.forEach(entry => {
// Set visibility FLAG
- const key = entry.target.id || entry.target.className;
- visibilityMap[key] = entry.isIntersecting;
+ const key = entry.target.id || entry.target.className
+ visibilityMap[key] = entry.isIntersecting
// Handle COVER
if (entry.target.className === 'cover-main') {
if (entry.isIntersecting) {
// Reset colors
- document.querySelector('#kudoai a').style.color = 'white';
+ document.querySelector('#kudoai a').style.color = 'white'
window.starColor = 'white';
(document.querySelector('#scrollbar-style') || {}).innerText = (
':root { scrollbar-color: rgb(210,210,210) #1a1a1a }'
- + 'body::-webkit-scrollbar-thumb { background-color: white }');
+ + 'body::-webkit-scrollbar-thumb { background-color: white }')
// Animate KudoAI logo
- const kudo = document.querySelector('.kudo');
- kudo.classList.add('hover');
- setTimeout(() => { kudo.classList.remove('hover'); }, 955);
+ const kudo = document.querySelector('.kudo')
+ kudo.classList.add('hover')
+ setTimeout(() => { kudo.classList.remove('hover') }, 955)
// Scramble entire tagline + add case randomization layer
Array.from( // clear tagline spans to maintain grow effect
document.querySelectorAll('span[id^="tagline"]'))
- .forEach(span => { span.textContent = ''; });
- scrambleText([taglineWords[0]], document.querySelector('#tagline-pre-adj'));
- scrambleText(taglineWords[1], document.querySelector('#tagline-adj'), 750);
- scrambleText([taglineWords[2]], document.querySelector('#tagline-post-adj'));
- randomizeCase(document.querySelector('#tagline-pre-adj'));
- randomizeCase(document.querySelector('#tagline-post-adj'));
+ .forEach(span => { span.textContent = '' })
+ scrambleText([taglineWords[0]], document.querySelector('#tagline-pre-adj'))
+ scrambleText(taglineWords[1], document.querySelector('#tagline-adj'), 750)
+ scrambleText([taglineWords[2]], document.querySelector('#tagline-post-adj'))
+ randomizeCase(document.querySelector('#tagline-pre-adj'))
+ randomizeCase(document.querySelector('#tagline-post-adj'))
// Star boost
if (window.starVelocity.z <= iniStarZvelocity) { // to avoid reverse boost from scroll-ups
- window.starVelocity.z += .024; // boost velocity
+ window.starVelocity.z += .024 // boost velocity
setTimeout(() => { // slow velocity
- window.starVelocity.z -= .02; }, 1155);
+ window.starVelocity.z -= .02 }, 1155)
setTimeout(() => { // slow velocity to original
- window.starVelocity.z = iniStarZvelocity; }, 1355);
+ window.starVelocity.z = iniStarZvelocity }, 1355)
}
} else // stop scrambling tagline adjective
- clearTimeout(scrambleText.timeoutID);
+ clearTimeout(scrambleText.timeoutID)
// Handle FEATURE LIST
} else if (entry.target.id === 'feature-list') { // type features or clear content/timeouts
- if (entry.isIntersecting) typeText(features, entry.target, 20);
- else { entry.target.innerHTML = ''; clearTimeout(typeText.timeoutID); }
+ if (entry.isIntersecting) typeText(features, entry.target, 20)
+ else { entry.target.innerHTML = '' ; clearTimeout(typeText.timeoutID) }
}
-});});
+})})
const onLoadObserver = new MutationObserver(() => {
// Exit if not loaded
- if (!document.querySelector('.cover-main blockquote p')) return;
+ if (!document.querySelector('.cover-main blockquote p')) return
// Activate SMOOTH SCROLL
- smoothScroll(document, 155, 9);
+ smoothScroll(document, 155, 9)
// Hack HOMEPAGE
if (/#\/(?:\w{2}(?:-\w{2})?\/)?$/.test(location.hash)) {
// Hide SIDEBAR
- if (!isMobileDevice()) document.body.className = 'ready close';
+ if (!isMobileDevice()) document.body.className = 'ready close'
// Populate [taglineWords] for iObserver's scrambleText() + randomizeCase()
- const taglineSpans = Array.from(document.querySelectorAll('span[id^="tagline"]'));
+ const taglineSpans = Array.from(document.querySelectorAll('span[id^="tagline"]'))
taglineSpans.map(span => { taglineWords.push(
- /pre|post/.exec(span.id) ? span.textContent : span.textContent.split('|')); });
- taglineSpans.forEach(span => { span.textContent = ''; }); // clear them out
+ /pre|post/.exec(span.id) ? span.textContent : span.textContent.split('|')) })
+ taglineSpans.forEach(span => { span.textContent = '' }) // clear them out
// Observe COVER for visibility change tagline hacks
- iObserver.observe(document.querySelector('.cover-main'));
+ iObserver.observe(document.querySelector('.cover-main'))
// Add TOP GRADIENT
const cover = document.querySelector('.cover'),
- topGradient = document.createElement('div');
- topGradient.classList.add('top-gradient');
- document.body.append(topGradient);
- updateTGvisibility(); // since page load can be below fold
+ topGradient = document.createElement('div')
+ topGradient.classList.add('top-gradient')
+ document.body.append(topGradient)
+ updateTGvisibility() // since page load can be below fold
function updateTGvisibility() {
topGradient.style.display = ( // hide/show when fold is 85% at top
- window.scrollY > 0.85 * cover.offsetHeight ? '' : 'none' ); }
+ window.scrollY > 0.85 * cover.offsetHeight ? '' : 'none' ) }
mdLoaded.then(() => {
// Scroll slightly to overcome Chromium bug preventing parallax
if (navigator.userAgent.includes('Chrome'))
- window.scrollBy(0, 200); setTimeout(() => window.scrollBy(0, -200), 600);
+ window.scrollBy(0, 200); setTimeout(() => window.scrollBy(0, -200), 600)
// Disable SEARCH
- document.querySelector('.search').style.display = 'none';
- document.querySelector('.sidebar-nav').style.paddingTop = '102px';
+ document.querySelector('.search').style.display = 'none'
+ document.querySelector('.sidebar-nav').style.paddingTop = '102px'
// Create/select FEATURE LIST
const featureListDiv = document.querySelector('#feature-list') || // select div
- document.createElement('div'); // ...or create it
+ document.createElement('div') // ...or create it
if (!featureListDiv.parentElement) { // append created div if not in DOM
- featureListDiv.setAttribute('id', 'feature-list');
- const introDiv = document.querySelector('#intro');
+ featureListDiv.setAttribute('id', 'feature-list')
+ const introDiv = document.querySelector('#intro')
introDiv.parentElement.insertBefore( // insert after description
- featureListDiv, introDiv.nextElementSibling.nextElementSibling);
+ featureListDiv, introDiv.nextElementSibling.nextElementSibling)
}
// ...then observe for visibility change to apply typing hack
- iObserver.observe(featureListDiv);
+ iObserver.observe(featureListDiv)
// Append COPYRIGHT NOTICE footer
const article = document.querySelector('article'), // to insert at end of
- copyrightFooter = document.createElement('div');
- copyrightFooter.id = 'copyright-footer';
+ copyrightFooter = document.createElement('div')
+ copyrightFooter.id = 'copyright-footer'
copyrightFooter.innerHTML = 'Copyright © 2023–' + new Date().getFullYear()
+ ' KudoAI.
'
+ 'Designed by Adam Lui / '
+ 'Powered by Docsify / '
- + 'Hosted by GitHub';
- article.append(copyrightFooter);
+ + 'Hosted by GitHub'
+ article.append(copyrightFooter)
// Replace GitHub demo embed w/ YouTube one
const ghDemo = document.querySelector('a[href*="/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3140b0f8a4"]'),
- ytDemo = document.createElement('iframe');
- ytDemo.setAttribute('width', '855'); ytDemo.setAttribute('height', '455');
- ytDemo.setAttribute('src', 'https://www.youtube.com/embed/yG8DtsEo0PM?rel=0');
+ ytDemo = document.createElement('iframe')
+ ytDemo.setAttribute('width', '855'); ytDemo.setAttribute('height', '455')
+ ytDemo.setAttribute('src', 'https://www.youtube.com/embed/yG8DtsEo0PM?rel=0')
ytDemo.allow = 'web-share' + ( !navigator.userAgent.includes('Firefox') ?
- 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share' : '' );
- ytDemo.setAttribute('allowfullscreen', '');
- ytDemo.style.minWidth = 'fit-content'; ytDemo.style.width = '855px'; ytDemo.style.marginBottom = '30px';
- ghDemo.parentNode.replaceChild(ytDemo, ghDemo);
- ytDemo.parentNode.style.textAlign = 'center';
+ 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share' : '' )
+ ytDemo.setAttribute('allowfullscreen', '')
+ ytDemo.style.minWidth = 'fit-content'; ytDemo.style.width = '855px'; ytDemo.style.marginBottom = '30px'
+ ghDemo.parentNode.replaceChild(ytDemo, ghDemo)
+ ytDemo.parentNode.style.textAlign = 'center'
// Strip blockquote wrappers from showcase app descriptions
document.querySelectorAll('blockquote').forEach(blockquote => {
- const parent = blockquote.parentNode, content = blockquote.innerHTML;
- parent.replaceChild(document.createRange().createContextualFragment(content), blockquote);
- });
+ const parent = blockquote.parentNode, content = blockquote.innerHTML
+ parent.replaceChild(document.createRange().createContextualFragment(content), blockquote)
+ })
// Convert weserv.nl img srcs in contributor avatars into renderable ones
document.querySelectorAll('img[src], source[srcset]').forEach(elem => {
@@ -172,31 +172,31 @@ const onLoadObserver = new MutationObserver(() => {
})
// Add FADE classes to elements
- const fadeUpElements = [], fadeRightElements = [], fadeLeftElements = [];
+ const fadeUpElements = [], fadeRightElements = [], fadeLeftElements = []
fadeUpElements.push(...document.querySelectorAll(
'.cover-main img, .cover-main a,' // cover elements
+ 'h2, h3, p, pre, main li,' // general elements
- + 'div#partners-collage, #copyright-footer')); // footer elements
- fadeUpElements.forEach((element) => { element.classList.add('content-fadeup'); });
+ + 'div#partners-collage, #copyright-footer')) // footer elements
+ fadeUpElements.forEach((element) => { element.classList.add('content-fadeup') })
fadeUpElements.push( // language selector
- document.querySelector('#language-menu'));
- fadeUpElements[fadeUpElements.length - 1].classList.add('menu-fadeup');
+ document.querySelector('#language-menu'))
+ fadeUpElements[fadeUpElements.length - 1].classList.add('menu-fadeup')
fadeRightElements.push(...document.querySelectorAll( // left-side showcase apps
`#showcase ~ h3:nth-of-type(odd):not(#contributors ~ *),
- #showcase ~ h3 + p:nth-of-type(odd):not(#contributors ~ *`));
- fadeRightElements.forEach((element) => { element.classList.add('content-faderight'); });
+ #showcase ~ h3 + p:nth-of-type(odd):not(#contributors ~ *`))
+ fadeRightElements.forEach((element) => { element.classList.add('content-faderight') })
fadeLeftElements.push(...document.querySelectorAll( // right-side showcase apps
`#showcase ~ h3:nth-of-type(even):not(#contributors ~ *),
- #showcase ~ h3 + p:nth-of-type(even):not(#contributors ~ *`));
- fadeLeftElements.forEach((element) => { element.classList.add('content-fadeleft'); });
- const fadeElements = [...fadeUpElements, ...fadeRightElements, ...fadeLeftElements];
+ #showcase ~ h3 + p:nth-of-type(even):not(#contributors ~ *`))
+ fadeLeftElements.forEach((element) => { element.classList.add('content-fadeleft') })
+ const fadeElements = [...fadeUpElements, ...fadeRightElements, ...fadeLeftElements]
// ...then observe for visibility change to update element/sidebar states
- const sideNavItems = [...document.querySelectorAll('.sidebar-nav li')];
+ const sideNavItems = [...document.querySelectorAll('.sidebar-nav li')]
const fadeObserver = new IntersectionObserver(
(entries) => { entries.forEach((entry) => {
if (entry.isIntersecting) {
- entry.target.classList.add('visible');
+ entry.target.classList.add('visible')
// Update sidebar w/ active class for headings
if (entry.target.tagName.startsWith('H')) {
@@ -204,39 +204,39 @@ const onLoadObserver = new MutationObserver(() => {
// Find the nav item that matches intersecting heading
const headingText = entry.target.querySelector('a').textContent,
activeNavItem = (document.querySelector(
- `a[title="${ headingText }"]`) || {}).parentElement;
+ `a[title="${ headingText }"]`) || {}).parentElement
// Add `nav-active` class to matched nav item
if (activeNavItem) {
- sideNavItems.forEach(item => item.classList.remove('nav-active'));
- activeNavItem.classList.add('nav-active');
+ sideNavItems.forEach(item => item.classList.remove('nav-active'))
+ activeNavItem.classList.add('nav-active')
}
}
- } else entry.target.classList.remove('visible');
- });}, { root: null, threshold: 0.02 });
- fadeElements.forEach((element) => { fadeObserver.observe(element); });
+ } else entry.target.classList.remove('visible')
+ })}, { root: null, threshold: 0.02 })
+ fadeElements.forEach((element) => { fadeObserver.observe(element) })
// Change stars shield link to repo
const starsShieldLink = document.querySelector('a[href$="stargazers"]'),
- href = starsShieldLink.getAttribute('href');
- starsShieldLink.setAttribute('href', href.replace('/stargazers', ''));
+ href = starsShieldLink.getAttribute('href')
+ starsShieldLink.setAttribute('href', href.replace('/stargazers', ''))
// Establish TRIGGER POINTS for scroll FX
- const triggerElements = [], triggerPoints = [];
- triggerElements.push(...document.querySelectorAll('h2'));
- triggerElements.push(document.querySelector('h3#-greasemonkey'));
- triggerElements.push(document.querySelector('h3#-chrome'));
+ const triggerElements = [], triggerPoints = []
+ triggerElements.push(...document.querySelectorAll('h2'))
+ triggerElements.push(document.querySelector('h3#-greasemonkey'))
+ triggerElements.push(document.querySelector('h3#-chrome'))
triggerElements.push( // 1st showcase tile
- document.querySelector('img[src*="chatgpt-infinity"]'));
+ document.querySelector('img[src*="chatgpt-infinity"]'))
triggerElements.forEach(element => {
- const elementPos = element.getBoundingClientRect().top;
+ const elementPos = element.getBoundingClientRect().top
const vOffsetDivisor = ( // higher = lower pos
element.id.includes('⚡') ? 1.5 // Importing the Library section
: element.tagName === 'IMG' ? 0.8 // 1st showcase tile
- : 8.8 ); // headings
- triggerPoints.push(elementPos - window.innerHeight/vOffsetDivisor);
- });
- triggerPoints.sort((a, b) => a - b); // sort ascending
+ : 8.8 ) // headings
+ triggerPoints.push(elementPos - window.innerHeight/vOffsetDivisor)
+ })
+ triggerPoints.sort((a, b) => a - b) // sort ascending
// Update COLORS + STAR VELOCITY on scroll
window.addEventListener('scroll', () => {
@@ -245,55 +245,55 @@ const onLoadObserver = new MutationObserver(() => {
if (visibilityMap['cover-main'] || visibilityMap['feature-list']) return;
// Determine current section
- let currentSection = 0;
+ let currentSection = 0
while (window.scrollY > triggerPoints[currentSection] &&
currentSection < triggerPoints.length)
- currentSection++;
+ currentSection++
// Color/animate logo/stars + color scrollbar if section changed
- const sectionColor = sectionColors[currentSection - 2];
+ const sectionColor = sectionColors[currentSection - 2]
if (sectionColor !== window.starColor) {
// Color/animate stars
- window.starColor = sectionColor;
+ window.starColor = sectionColor
setTimeout(() => { // schedule color reset
if (window.starVelocity.z <= iniStarZvelocity) {
- window.starColor = 'white'; }}, warpDuration + starResetDelay);
- window.starVelocity.z += .0045; // boost velocity
+ window.starColor = 'white' }}, warpDuration + starResetDelay)
+ window.starVelocity.z += .0045 // boost velocity
setTimeout(() => { // slow velocity
- window.starVelocity.z = Math.max(iniStarZvelocity, window.starVelocity.z - .0025);
- }, hiWarpDuration);
+ window.starVelocity.z = Math.max(iniStarZvelocity, window.starVelocity.z - .0025)
+ }, hiWarpDuration)
setTimeout(() => { // slow velocity to original
- window.starVelocity.z = Math.max(iniStarZvelocity, window.starVelocity.z - .002);
- }, warpDuration);
+ window.starVelocity.z = Math.max(iniStarZvelocity, window.starVelocity.z - .002)
+ }, warpDuration)
// Color/animate logo
const kudoAIlogo = document.querySelector('#kudoai a'),
- kudo = document.querySelector('.kudo');
- kudoAIlogo.style.color = sectionColor;
- kudo.classList.add('hover'); // trigger slide animation
+ kudo = document.querySelector('.kudo')
+ kudoAIlogo.style.color = sectionColor
+ kudo.classList.add('hover') // trigger slide animation
setTimeout(() => { // schedule color/animation reset
if (window.starVelocity.z <= iniStarZvelocity) {
- kudoAIlogo.style.color = 'white';
- kudo.classList.remove('hover');
- }}, warpDuration + 5);
+ kudoAIlogo.style.color = 'white'
+ kudo.classList.remove('hover')
+ }}, warpDuration + 5)
// Color scrollbar
const scrollbarStyle = document.querySelector('#scrollbar-style') || // select div
- document.createElement('style'); // ...or create it
+ document.createElement('style') // ...or create it
if (!scrollbarStyle.parentElement) { // append created div if not in DOM
- scrollbarStyle.setAttribute('id', 'scrollbar-style');
- document.head.append(scrollbarStyle);
+ scrollbarStyle.setAttribute('id', 'scrollbar-style')
+ document.head.append(scrollbarStyle)
}
scrollbarStyle.innerText = (
`:root { scrollbar-color: ${ sectionColor } #1a1a1a }`
- + `body::-webkit-scrollbar-thumb { background-color: ${ sectionColor } }`);
+ + `body::-webkit-scrollbar-thumb { background-color: ${ sectionColor } }`)
setTimeout(() => { // schedule color reset
if (window.starVelocity.z <= iniStarZvelocity) {
scrollbarStyle.innerText = (
':root { scrollbar-color: rgb(210,210,210) #1a1a1a }'
- + 'body::-webkit-scrollbar-thumb { background-color: white }');
- }}, warpDuration + 5);
+ + 'body::-webkit-scrollbar-thumb { background-color: white }')
+ }}, warpDuration + 5)
}
});
@@ -302,51 +302,51 @@ const onLoadObserver = new MutationObserver(() => {
document.querySelectorAll('picture').forEach(picture => {
const srcElement = picture.querySelector('source'),
srcSet = srcElement.getAttribute('srcset'),
- imgElement = document.createElement('img');
- imgElement.setAttribute('src', srcSet);
- picture.parentNode.replaceChild(imgElement, picture);
- });
+ imgElement = document.createElement('img')
+ imgElement.setAttribute('src', srcSet)
+ picture.parentNode.replaceChild(imgElement, picture)
+ })
// Append EMAIL SIGNUP footer
const partnersCollage = document.getElementById('partners-collage'), // to insert after
- emailFooter = document.createElement('div');
+ emailFooter = document.createElement('div')
fetch('assets/html/footer.html')
.then(response => response.text()).then(html => {
- emailFooter.innerHTML = html;
- partnersCollage.insertAdjacentElement('afterend', emailFooter);
- });
+ emailFooter.innerHTML = html
+ partnersCollage.insertAdjacentElement('afterend', emailFooter)
+ })
// Remove readme's BACK-TO-TOP link
- const readmeBTTlink = [...document.querySelectorAll('a')].find(link => link.textContent.includes('↑'));
- readmeBTTlink?.previousSibling.remove(); readmeBTTlink?.remove();
+ const readmeBTTlink = [...document.querySelectorAll('a')].find(link => link.textContent.includes('↑'))
+ readmeBTTlink?.previousSibling.remove() ; readmeBTTlink?.remove()
setTimeout(() => { // Add PARALLAX
// Target TRIGGERS
- const parallaxTriggers = [];
+ const parallaxTriggers = []
document.querySelectorAll('#main, h2:not([id="about"])').forEach(trigger => {
- const y = trigger.getBoundingClientRect().top - window.innerHeight / 1.2;
- const triggerElem = trigger.tagName === 'H2' ? trigger.parentElement : trigger;
- parallaxTriggers.push({ element: triggerElem, y });
- });
+ const y = trigger.getBoundingClientRect().top - window.innerHeight / 1.2
+ const triggerElem = trigger.tagName === 'H2' ? trigger.parentElement : trigger
+ parallaxTriggers.push({ element: triggerElem, y })
+ })
// Add SCROLL listener
window.addEventListener('scroll', () => {
- updateTGvisibility();
+ updateTGvisibility()
parallaxTriggers.forEach(trigger => {
if (window.scrollY >= trigger.y && window.scrollY < trigger.y + window.innerHeight) {
// Target previous elements to hack
- const prevElems = [];
+ const prevElems = []
if (trigger.element.id === 'main')
- prevElems.push(document.querySelector('.cover-main'));
+ prevElems.push(document.querySelector('.cover-main'))
else { // target previous 6 siblings
- let currentElem = trigger.element.previousElementSibling;
- for (let i = 0; i < 7; i++) {
+ let currentElem = trigger.element.previousElementSibling
+ for (let i = 0 ; i < 7 ; i++) {
if (currentElem) {
- prevElems.push(currentElem);
- currentElem = currentElem.previousElementSibling;
- } else break;
+ prevElems.push(currentElem)
+ currentElem = currentElem.previousElementSibling
+ } else break
}
}
@@ -359,49 +359,49 @@ const onLoadObserver = new MutationObserver(() => {
parallaxOffset = topGap * -0.55,
scaleDelay = 285, // px from trigger.y to delay scaling
scaleFactor = topGap > -scaleDelay ? 1
- : 1 - Math.abs(topGap + scaleDelay) / 5 / window.innerHeight;
+ : 1 - Math.abs(topGap + scaleDelay) / 5 / window.innerHeight
- try { elem.classList.remove('content-fadeup'); } catch (err) {}
- elem.style.opacity = newOpacity;
- elem.style.transform = `translateY(${parallaxOffset}px) scale(${scaleFactor})`;
- elem.style.filter = `blur(${blurAmount}px)`;
- });
+ try { elem.classList.remove('content-fadeup') } catch (err) {}
+ elem.style.opacity = newOpacity
+ elem.style.transform = `translateY(${parallaxOffset}px) scale(${scaleFactor})`
+ elem.style.filter = `blur(${blurAmount}px)`
+ })
- }});});}, 100);
- });
+ }})})}, 100)
+ })
// Hide SITE LANG SELECTOR from NON-HOME pages
- } else document.querySelector('.app-nav').style.display = 'none';
+ } else document.querySelector('.app-nav').style.display = 'none'
// Hack LICENSE/SECURIY pages
if (/LICENSE|SECURITY/.test(location.hash)) {
// Hide SIDEBAR
- if (!isMobileDevice()) document.body.className = 'ready close';
+ if (!isMobileDevice()) document.body.className = 'ready close'
// Correct DOC LANG SELECTOR links
mdLoaded.then(() => {
- const docLangSelector = document.querySelectorAll('h5 a');
+ const docLangSelector = document.querySelectorAll('h5 a')
for (const lang of docLangSelector)
- lang.href = lang.href.replace(/(https?:\/\/[^/]+\/)([^.]+)\.md/, '$1#/$2');
- });
+ lang.href = lang.href.replace(/(https?:\/\/[^/]+\/)([^.]+)\.md/, '$1#/$2')
+ })
}
// DISCONNECT observer
- onLoadObserver.disconnect();
+ onLoadObserver.disconnect()
-});
+})
// Define FUNCTIONS
function isMobileDevice() {
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); }
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) }
function validateIntArg(arg, name, defaultVal) {
- if (arg === undefined) return defaultVal; // no validation required
+ if (arg === undefined) return defaultVal // no validation required
if (!Number.isInteger(arg) && !/^\d+$/.test(arg))
- throw new Error(name + ' must be an integer.');
- return parseInt(arg, 10);
+ throw new Error(name + ' must be an integer.')
+ return parseInt(arg, 10)
}
function smoothScroll(target, speed, smooth) {
@@ -411,40 +411,40 @@ function smoothScroll(target, speed, smooth) {
target = (document.scrollingElement
|| document.documentElement
|| document.body.parentNode
- || document.body); // cross browser support for document scrolling
+ || document.body) // cross browser support for document scrolling
// Init variables
- let moving = false, pos = target.scrollTop;
+ let moving = false, pos = target.scrollTop
const frame = target === document.body && document.documentElement
? document.documentElement
- : target; // safari
+ : target // safari
// Add listeners
- target.addEventListener('mousewheel', scrolled, { passive: false });
- target.addEventListener('DOMMouseScroll', scrolled, { passive: false });
+ target.addEventListener('mousewheel', scrolled, { passive: false })
+ target.addEventListener('DOMMouseScroll', scrolled, { passive: false })
function scrolled(e) {
- e.preventDefault(); // disable default scrolling
- const delta = normalizeWheelDelta(e);
- pos += -delta * speed;
+ e.preventDefault() // disable default scrolling
+ const delta = normalizeWheelDelta(e)
+ pos += -delta * speed
pos = ( // limit scrolling
- Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)));
- if (!moving) update();
+ Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)))
+ if (!moving) update()
}
function normalizeWheelDelta(e) {
if (e.detail) {
if (e.wheelDelta)
- return e.wheelDelta/e.detail/40 * (e.detail>0 ? 1 : -1); // Opera
- else return -e.detail/3; // Firefox
- } else return e.wheelDelta/120; // IE/Safari/Chrome
+ return e.wheelDelta/e.detail/40 * (e.detail>0 ? 1 : -1) // Opera
+ else return -e.detail/3 // Firefox
+ } else return e.wheelDelta/120 // IE/Safari/Chrome
}
function update() {
- moving = true;
- const delta = (pos - target.scrollTop) / smooth;
- target.scrollTop += delta;
- if (Math.abs(delta) > 0.5) requestFrame(update);
- else moving = false;
+ moving = true
+ const delta = (pos - target.scrollTop) / smooth
+ target.scrollTop += delta
+ if (Math.abs(delta) > 0.5) requestFrame(update)
+ else moving = false
}
const requestFrame = function() { // requestAnimationFrame cross browser
@@ -455,30 +455,30 @@ function smoothScroll(target, speed, smooth) {
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(func) { window.setTimeout(func, 1000 / 50); }
- );
- }();
+ )
+ }()
}
function scrambleText(text, destination, delayBetweenWords, textIdx = 0) {
// Validate args
- if (typeof text === 'string') text = [text]; // array of strings to scramble
+ if (typeof text === 'string') text = [text] // array of strings to scramble
if (!destination?.nodeName) // DOM element to scramble to
- throw new Error('Destination (2nd arg) must be a DOM element');
+ throw new Error('Destination (2nd arg) must be a DOM element')
if (delayBetweenWords) { // ms to delay between scrambles
if (!Number.isInteger(delayBetweenWords) && !/^\d+$/.test(delayBetweenWords))
- throw new Error('Delay betweeen words (3nd arg) must be an integer (ms)');
- delayBetweenWords = parseInt(delayBetweenWords, 10);
+ throw new Error('Delay betweeen words (3nd arg) must be an integer (ms)')
+ delayBetweenWords = parseInt(delayBetweenWords, 10)
}
// Scramble text
- const textToScramble = new Scramble(destination);
+ const textToScramble = new Scramble(destination)
textToScramble.setText(text[textIdx])
.then(() => { if (delayBetweenWords && visibilityMap['cover-main']) {
scrambleText.timeoutID = setTimeout(() => {
- scrambleText(text, destination, delayBetweenWords, (textIdx + 1) % text.length); },
- delayBetweenWords);
- }});
+ scrambleText(text, destination, delayBetweenWords, (textIdx + 1) % text.length) },
+ delayBetweenWords)
+ }})
}
function randomizeCase(targetNode, iniDelay, finalDelay, incrementA, incrementB, inflectionPt) {
@@ -487,130 +487,130 @@ function randomizeCase(targetNode, iniDelay, finalDelay, incrementA, incrementB,
if (!targetNode?.nodeName) // DOM element to randomize case of text content
throw new Error('Target node (1st arg) must be a DOM element');
iniDelay = validateIntArg( // ms to initially between case switches
- iniDelay, 'Initial delay', 5);
+ iniDelay, 'Initial delay', 5)
finalDelay = validateIntArg( // ms to finally delay between case switches
- finalDelay, 'Final delay', 1000);
+ finalDelay, 'Final delay', 1000)
incrementA = validateIntArg( // ms to initially increment from iniDelay to finalDelay
- incrementA, 'Increment A', 10);
+ incrementA, 'Increment A', 10)
incrementB = validateIntArg( // ms to increment from iniDelay to finalDelay after inflection
- incrementB, 'Increment B', 111);
+ incrementB, 'Increment B', 111)
inflectionPt = validateIntArg( // ms of iniDelay state before inflecting to Increment B
- inflectionPt, 'Inflection point', 265);
+ inflectionPt, 'Inflection point', 265)
// Randomize case
targetNode.textContent = targetNode.textContent.split('').map(letter => {
- return Math.random() < 0.5 ? letter.toUpperCase() : letter.toLowerCase();
- }).join('');
- randomizeCase.iniDelay = randomizeCase.iniDelay || iniDelay;
- randomizeCase.iniDelay += randomizeCase.iniDelay < inflectionPt ? incrementA : incrementB;
- if (randomizeCase.iniDelay > finalDelay) randomizeCase.iniDelay = finalDelay; // cap at `finalDelay`
+ return Math.random() < 0.5 ? letter.toUpperCase() : letter.toLowerCase()
+ }).join('')
+ randomizeCase.iniDelay = randomizeCase.iniDelay || iniDelay
+ randomizeCase.iniDelay += randomizeCase.iniDelay < inflectionPt ? incrementA : incrementB
+ if (randomizeCase.iniDelay > finalDelay) randomizeCase.iniDelay = finalDelay // cap at `finalDelay`
setTimeout(() => {
- randomizeCase(targetNode, iniDelay, finalDelay, incrementA, incrementB, inflectionPt);
- }, randomizeCase.iniDelay);
+ randomizeCase(targetNode, iniDelay, finalDelay, incrementA, incrementB, inflectionPt)
+ }, randomizeCase.iniDelay)
}
function typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos, linesToScrollAt) {
// Validate args
- if (typeof txtToType === 'string') txtToType = [txtToType]; // array of strings to type
+ if (typeof txtToType === 'string') txtToType = [txtToType] // array of strings to type
if (!destination?.nodeName) // DOM element to type to
- throw new Error('Destination must be a DOM element');
+ throw new Error('Destination must be a DOM element')
typeDelay = validateIntArg( // ms to delay between chars typed
- typeDelay, 'Typing delay', 30);
+ typeDelay, 'Typing delay', 30)
iniTxtToType = validateIntArg( // index of txt array to start typing
- iniTxtToType, 'Initial text array index', 0);
+ iniTxtToType, 'Initial text array index', 0)
iniTxtPos = validateIntArg( // position in txt string to start typing from
- iniTxtPos, 'Initial text string position', 3);
+ iniTxtPos, 'Initial text string position', 3)
linesToScrollAt = validateIntArg( // lines reached before scrolling up
- linesToScrollAt, 'Lines to scroll at', 5);
+ linesToScrollAt, 'Lines to scroll at', 5)
// Init variables
let typeContent = ' ',
- iniRow = Math.max(0, iniTxtToType - linesToScrollAt);
+ iniRow = Math.max(0, iniTxtToType - linesToScrollAt)
// Type text
- while (iniRow < iniTxtToType) typeContent += txtToType[iniRow++] + '
';
- destination.innerHTML = typeContent + txtToType[iniTxtToType].substring(0, iniTxtPos) + '_';
+ while (iniRow < iniTxtToType) typeContent += txtToType[iniRow++] + '
'
+ destination.innerHTML = typeContent + txtToType[iniTxtToType].substring(0, iniTxtPos) + '_'
if (iniTxtPos++ == txtToType[iniTxtToType].length) {
- iniTxtPos = 0; iniTxtToType++;
+ iniTxtPos = 0 ; iniTxtToType++
if (iniTxtToType != txtToType.length) { // if end of string reached
typeText.timeoutID = setTimeout(() => {
- typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos);
- }, 88); // pause til next string
+ typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos)
+ }, 88) // pause til next string
}} else typeText.timeoutID = setTimeout(() => {
- typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos);
- }, typeDelay + (Math.random() * 220) - 110);
+ typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos)
+ }, typeDelay + (Math.random() * 220) - 110)
}
// Define SCRAMBLE class
class Scramble {
constructor(el) {
- this.el = el;
- this.chars = '!<>-_\\/[]{}—=+*^?#________';
- this.update = this.update.bind(this);
+ this.el = el
+ this.chars = '!<>-_\\/[]{}—=+*^?#________'
+ this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText,
length = Math.max(oldText.length, newText.length),
- promise = new Promise((resolve) => this.resolve = resolve);
- this.queue = [];
- for (let i = 0; i < length; i++) {
+ promise = new Promise((resolve) => this.resolve = resolve)
+ this.queue = []
+ for (let i = 0 ; i < length ; i++) {
const from = oldText[i] || '',
to = newText[i] || '',
start = Math.floor(Math.random() * 45), // speed of beginning scramble
- end = start + Math.floor(Math.random() * 45); // speed of end scramble
- this.queue.push({ from, to, start, end });
+ end = start + Math.floor(Math.random() * 45) // speed of end scramble
+ this.queue.push({ from, to, start, end })
}
- cancelAnimationFrame(this.frameRequest);
- this.frame = 0; this.update(); return promise;
+ cancelAnimationFrame(this.frameRequest)
+ this.frame = 0 ; this.update() ; return promise
}
update() {
- let output = '', complete = 0;
- for (let i = 0, n = this.queue.length; i < n; i++) {
- let { from, to, start, end, char } = this.queue[i];
- if (this.frame >= end) { complete++; output += to; }
+ let output = '', complete = 0
+ for (let i = 0, n = this.queue.length ; i < n ; i++) {
+ let { from, to, start, end, char } = this.queue[i]
+ if (this.frame >= end) { complete++ ; output += to }
else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
- char = this.randomChar();
- this.queue[i].char = char;
+ char = this.randomChar()
+ this.queue[i].char = char
}
- output += `${ char }`;
- } else output += from;
+ output += `${ char }`
+ } else output += from
}
- this.el.innerHTML = output;
- if (complete === this.queue.length) this.resolve();
+ this.el.innerHTML = output
+ if (complete === this.queue.length) this.resolve()
else {
- this.frameRequest = requestAnimationFrame(this.update);
- this.frame++;
+ this.frameRequest = requestAnimationFrame(this.update)
+ this.frame++
}
}
randomChar() {
- return this.chars[Math.floor(Math.random() * this.chars.length)]; }
+ return this.chars[Math.floor(Math.random() * this.chars.length)] }
}
// Run MAIN routine
// Add listeners to language selector
const langMenu = document.getElementById('language-menu'),
- langSelector = document.getElementById('language-selector');
-let hideTimeout; // to account for gap between button & menu
+ langSelector = document.getElementById('language-selector')
+let hideTimeout // to account for gap between button & menu
langSelector.onmouseover = langSelector.onmouseout = langMenu.onmouseover = langMenu.onmouseout = event => {
- clearTimeout(hideTimeout);
- if (event.type == 'mouseover') langMenu.style.display = 'block';
+ clearTimeout(hideTimeout)
+ if (event.type == 'mouseover') langMenu.style.display = 'block'
else if (event.type == 'mouseout')
- hideTimeout = setTimeout(() => langMenu.style.display = 'none', 55);
+ hideTimeout = setTimeout(() => langMenu.style.display = 'none', 55)
};
document.querySelectorAll('#language-selector a').forEach(link => { // add listener to hide tooltips
- link.addEventListener('mouseenter', () => { link.removeAttribute('title'); });});
+ link.addEventListener('mouseenter', () => { link.removeAttribute('title') })})
document.querySelectorAll('.dropdown-link').forEach(link => { // add listener to dismisss menu
- link.addEventListener('click', () => langMenu.style.display = 'none');});
+ link.addEventListener('click', () => langMenu.style.display = 'none')})
// Observe for load + re-connect on nav to new hash
-onLoadObserver.observe(document.body, { childList: true, subtree: true });
-let fromUnhashedURL = window.location.href.includes('#');
+onLoadObserver.observe(document.body, { childList: true, subtree: true })
+let fromUnhashedURL = window.location.href.includes('#')
window.addEventListener('hashchange', () => {
- if (!fromUnhashedURL) fromUnhashedURL = true;
+ if (!fromUnhashedURL) fromUnhashedURL = true
else if (fromUnhashedURL)
- onLoadObserver.observe(document.body, { childList: true, subtree: true });
+ onLoadObserver.observe(document.body, { childList: true, subtree: true })
});
diff --git a/docs/assets/js/src/starry-background.js b/docs/assets/js/src/starry-background.js
index 9b55c08b0..c9f97e663 100644
--- a/docs/assets/js/src/starry-background.js
+++ b/docs/assets/js/src/starry-background.js
@@ -3,109 +3,109 @@
* . . . * . . * */
// Init variables
-window.starColor = 'white';
-window.starVelocity = { x: 0, y: 0, tx: 0, ty: 0, z: 0.0005 };
+window.starColor = 'white'
+window.starVelocity = { x: 0, y: 0, tx: 0, ty: 0, z: 0.0005 }
const starSize = 6, starMinScale = 0.00000000025, overflowThreshold = 50,
starCount = ( window.innerWidth + window.innerHeight ) /
( navigator.userAgent.indexOf('Firefox') > -1 ? 18 : 11 ),
canvas = document.querySelector( 'canvas' ),
- context = canvas.getContext( '2d' );
+ context = canvas.getContext( '2d' )
let scale = 0.5, // device pixel ratio
stars = [], width, height, pointerX, pointerY,
- touchInput = false;
+ touchInput = false
// Generate/animate stars
-for (let i = 0; i < starCount; i++)
- stars.push({ x: 0, y: 0, z: starMinScale + Math.random() * ( 1 - starMinScale )});
-updateCanvasSize(); animateStars();
+for (let i = 0 ; i < starCount ; i++)
+ stars.push({ x: 0, y: 0, z: starMinScale + Math.random() * ( 1 - starMinScale )})
+updateCanvasSize() ; animateStars()
// Add listeners
-window.onresize = updateCanvasSize;
+window.onresize = updateCanvasSize
document.onmousemove = (event) => {
- touchInput = false; movePointer(event.clientX, event.clientY);
-};
+ touchInput = false ; movePointer(event.clientX, event.clientY)
+}
document.ontouchmove = (event) => {
- touchInput = true;
- movePointer(event.touches[0].clientX, event.touches[0].clientY);
- event.preventDefault();
-};
-document.ontouchend = () => { pointerX = null; pointerY = null; };
-document.onmouseleave = () => { pointerX = null; pointerY = null; };
+ touchInput = true
+ movePointer(event.touches[0].clientX, event.touches[0].clientY)
+ event.preventDefault()
+}
+document.ontouchend = () => { pointerX = null ; pointerY = null }
+document.onmouseleave = () => { pointerX = null ; pointerY = null }
// Define FUNCTIONS
function updateCanvasSize() {
- width = window.innerWidth * scale; height = window.innerHeight * scale;
- canvas.width = width; canvas.height = height;
+ width = window.innerWidth * scale; height = window.innerHeight * scale
+ canvas.width = width ; canvas.height = height
stars.forEach((star) => { // position it
- star.x = Math.random() * width; star.y = Math.random() * height; });
+ star.x = Math.random() * width ; star.y = Math.random() * height })
}
function animateStars() {
// Clear previous frame
- context.clearRect(0, 0, width, height);
+ context.clearRect(0, 0, width, height)
// Update star positions
- window.starVelocity.tx *= 0.86; window.starVelocity.ty *= 0.86; // proportional to momentum
- window.starVelocity.x += ( window.starVelocity.tx - window.starVelocity.x ) * 0.8;
- window.starVelocity.y += ( window.starVelocity.ty - window.starVelocity.y ) * 0.8;
+ window.starVelocity.tx *= 0.86 ; window.starVelocity.ty *= 0.86 // proportional to momentum
+ window.starVelocity.x += ( window.starVelocity.tx - window.starVelocity.x ) * 0.8
+ window.starVelocity.y += ( window.starVelocity.ty - window.starVelocity.y ) * 0.8
stars.forEach((star) => {
- star.x += window.starVelocity.x * star.z;
- star.y += window.starVelocity.y * star.z;
- star.x += (star.x - width/2) * window.starVelocity.z * star.z;
- star.y += (star.y - height/2) * window.starVelocity.z * star.z;
- star.z += window.starVelocity.z;
+ star.x += window.starVelocity.x * star.z
+ star.y += window.starVelocity.y * star.z
+ star.x += (star.x - width/2) * window.starVelocity.z * star.z
+ star.y += (star.y - height/2) * window.starVelocity.z * star.z
+ star.z += window.starVelocity.z
// Recycle star when out-of-bounds
if (star.x < -overflowThreshold || star.x > width + overflowThreshold ||
star.y < -overflowThreshold || star.y > height + overflowThreshold) {
- let direction = 'z', vx = Math.abs(window.starVelocity.x), vy = Math.abs(window.starVelocity.y);
+ let direction = 'z', vx = Math.abs(window.starVelocity.x), vy = Math.abs(window.starVelocity.y)
if (vx > 1 || vy > 1) {
- let axis;
- if (vx > vy) axis = Math.random() < vx / ( vx + vy ) ? 'h' : 'v';
- else axis = Math.random() < vy / ( vx + vy ) ? 'v' : 'h';
- if (axis === 'h') direction = window.starVelocity.x > 0 ? 'l' : 'r';
- else direction = window.starVelocity.y > 0 ? 't' : 'b';
+ let axis
+ if (vx > vy) axis = Math.random() < vx / ( vx + vy ) ? 'h' : 'v'
+ else axis = Math.random() < vy / ( vx + vy ) ? 'v' : 'h'
+ if (axis === 'h') direction = window.starVelocity.x > 0 ? 'l' : 'r'
+ else direction = window.starVelocity.y > 0 ? 't' : 'b'
}
- star.z = starMinScale + Math.random() * ( 1 - starMinScale );
- if (direction === 'z') { star.z = 0.1; star.x = Math.random() * width; star.y = Math.random() * height; }
- else if (direction === 'l') { star.x = -overflowThreshold; star.y = height * Math.random(); }
- else if (direction === 'r') { star.x = width + overflowThreshold; star.y = height * Math.random(); }
- else if (direction === 't') { star.x = width * Math.random(); star.y = -overflowThreshold; }
- else if (direction === 'b') { star.x = width * Math.random(); star.y = height + overflowThreshold; }
+ star.z = starMinScale + Math.random() * ( 1 - starMinScale )
+ if (direction === 'z') { star.z = 0.1 ; star.x = Math.random() * width ; star.y = Math.random() * height }
+ else if (direction === 'l') { star.x = -overflowThreshold ; star.y = height * Math.random() }
+ else if (direction === 'r') { star.x = width + overflowThreshold ; star.y = height * Math.random() }
+ else if (direction === 't') { star.x = width * Math.random() ; star.y = -overflowThreshold }
+ else if (direction === 'b') { star.x = width * Math.random() ; star.y = height + overflowThreshold }
}
});
// Render stars
stars.forEach((star) => {
- context.beginPath();
- context.lineCap = 'round';
- context.lineWidth = starSize * star.z * scale;
- context.globalAlpha = 0.5 + 0.5*Math.random();
- context.strokeStyle = window.starColor;
- context.beginPath();
- context.moveTo( star.x, star.y );
+ context.beginPath()
+ context.lineCap = 'round'
+ context.lineWidth = starSize * star.z * scale
+ context.globalAlpha = 0.5 + 0.5*Math.random()
+ context.strokeStyle = window.starColor
+ context.beginPath()
+ context.moveTo( star.x, star.y )
let tailX = window.starVelocity.x * 2,
- tailY = window.starVelocity.y * 2;
+ tailY = window.starVelocity.y * 2
// stroke() wont work on an invisible line
- if (Math.abs(tailX) < 0.1) tailX = 0.5;
- if (Math.abs(tailY) < 0.1) tailY = 0.5;
+ if (Math.abs(tailX) < 0.1) tailX = 0.5
+ if (Math.abs(tailY) < 0.1) tailY = 0.5
- context.lineTo( star.x + tailX, star.y + tailY );
- context.stroke();
- });
+ context.lineTo( star.x + tailX, star.y + tailY )
+ context.stroke()
+ })
// Loop animation
- requestAnimationFrame(animateStars);
+ requestAnimationFrame(animateStars)
}
function movePointer(x, y) {
if (typeof pointerX === 'number' && typeof pointerY === 'number') {
- let ox = x - pointerX, oy = y - pointerY;
- window.starVelocity.tx = window.starVelocity.tx + ( ox / 8*scale ) * ( touchInput ? 1 : -1 );
- window.starVelocity.ty = window.starVelocity.ty + ( oy / 8*scale ) * ( touchInput ? 1 : -1 );
+ let ox = x - pointerX, oy = y - pointerY
+ window.starVelocity.tx = window.starVelocity.tx + ( ox / 8*scale ) * ( touchInput ? 1 : -1 )
+ window.starVelocity.ty = window.starVelocity.ty + ( oy / 8*scale ) * ( touchInput ? 1 : -1 )
}
- pointerX = x; pointerY = y;
+ pointerX = x ; pointerY = y
}