diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..19cc175
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,8 @@
+{
+ "trailingComma": "es5",
+ "useTabs": false,
+ "tabWidth": 4,
+ "semi": false,
+ "singleQuote": true,
+ "printWidth": 120
+}
diff --git a/src/assets/js/bundle.js b/src/assets/js/bundle.js
index 889186f..3710898 100644
--- a/src/assets/js/bundle.js
+++ b/src/assets/js/bundle.js
@@ -1,307 +1,345 @@
-"use strict";
+'use strict'
function $(s, all) {
- return all ? document.querySelectorAll(s) : document.querySelector(s);
+ return all ? document.querySelectorAll(s) : document.querySelector(s)
}
-let theme = localStorage.getItem("theme") || "theme-light"; // defaults
+let theme = localStorage.getItem('theme') || 'theme-light' // defaults
-const navButtons = $(".nav-buttons");
-const primaryNav = $(".nav");
-const themeToggle = $(".theme-toggle");
-const navToggle = $(".nav-toggle");
-const profileImage = $(".img-profile");
-const gpxMap = $("#biking-map");
-const pepe1 = "";
+const navButtons = $('.nav-buttons')
+const primaryNav = $('.nav')
+const themeToggle = $('.theme-toggle')
+const navToggle = $('.nav-toggle')
+const profileImage = $('.img-profile')
+const gpxMap = $('#biking-map')
+const pepe1 = ''
const goToHashed = (manualAnchor, marginTop) => {
if ((window.location.hash && window.location.hash.length) || manualAnchor) {
- const hashedElem = $(manualAnchor) || $(window.location.hash);
+ const hashedElem = $(manualAnchor) || $(window.location.hash)
// console.log("Going to hash: " + window.location.hash);
if (hashedElem) {
- hashedElem.style.scrollMarginTop = marginTop || "10px";
- hashedElem.scrollIntoView({ behavior: "smooth", block: "start" });
+ hashedElem.style.scrollMarginTop = marginTop || '10px'
+ hashedElem.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start',
+ })
}
}
-};
+}
// dom + sync js loaded - simply RnR!
window.addEventListener(
- "DOMContentLoaded",
+ 'DOMContentLoaded',
function () {
// homepage animations & where profile image is
if (profileImage) {
- profileImage.style.setProperty("--animate-duration", "0.5s");
- profileImage.addEventListener("click", () => animateProfileImage());
- profileImage.click();
+ profileImage.style.setProperty('--animate-duration', '0.5s')
+ profileImage.addEventListener('click', () => animateProfileImage())
+ profileImage.click()
// waving hand
- let heyHand = $(".hey-hand");
+ let heyHand = $('.hey-hand')
if (heyHand) {
- heyHand.style.setProperty("--animate-duration", "0.8s");
- heyHand.addEventListener("click", () => animateCSS(heyHand, "shakeX"));
+ heyHand.style.setProperty('--animate-duration', '0.8s')
+ heyHand.addEventListener('click', () =>
+ animateCSS(heyHand, 'shakeX')
+ )
this.setTimeout(() => {
- heyHand.click();
- }, 500);
+ heyHand.click()
+ }, 500)
const handInterval = setInterval(function () {
- heyHand.click();
- }, 5000);
+ heyHand.click()
+ }, 5000)
}
- let rocket = $("#rocket");
+ let rocket = $('#rocket')
if (rocket) {
setTimeout(() => {
- rocket.style.animation = "launch 1.5s forwards"; /* Adjust launch speed */
- }, 3000);
+ rocket.style.animation =
+ 'launch 1.5s forwards' /* Adjust launch speed */
+ }, 3000)
}
}
// keysdown for menu
document.onkeydown = function (e) {
- if (e.defaultPrevented) return;
- if (e.repeat) return;
+ if (e.defaultPrevented) return
+ if (e.repeat) return
switch (e.key) {
- case "Escape":
- if ("true" == primaryNav.getAttribute("data-opened")) {
- navToggle.click();
+ case 'Escape':
+ if ('true' == primaryNav.getAttribute('data-opened')) {
+ navToggle.click()
}
- break;
- case "m":
- navToggle.click();
- break;
- case "d":
- themeToggle.click();
- break;
+ break
+ case 'm':
+ navToggle.click()
+ break
+ case 'd':
+ themeToggle.click()
+ break
}
- };
+ }
// nav
- navToggle.addEventListener("click", () => {
- const visibility = primaryNav.getAttribute("data-opened");
- primaryNav.style.setProperty("--animate-duration", "0.2s");
+ navToggle.addEventListener('click', () => {
+ const visibility = primaryNav.getAttribute('data-opened')
+ primaryNav.style.setProperty('--animate-duration', '0.2s')
- if (visibility == "false") {
+ if (visibility == 'false') {
// move menu items to the body in order to avoid clipping problems.
- document.body.prepend(primaryNav);
- primaryNav.prepend(navToggle);
- navButtons.style.display = "none";
+ document.body.prepend(primaryNav)
+ primaryNav.prepend(navToggle)
+ navButtons.style.display = 'none'
- primaryNav.setAttribute("data-opened", "true");
+ primaryNav.setAttribute('data-opened', 'true')
- navToggle.setAttribute("aria-expanded", "true");
+ navToggle.setAttribute('aria-expanded', 'true')
- primaryNav.style.display = "flex";
- navToggle.classList.add("cross");
- animateCSS(".nav", "rubberBand").then((message) => {
- navToggle.focus(); // for accessibility
- });
- } else if (visibility == "true") {
- $(".header").append(primaryNav);
- $(".nav-buttons").append(navToggle);
+ primaryNav.style.display = 'flex'
+ navToggle.classList.add('cross')
+ animateCSS('.nav', 'rubberBand').then((message) => {
+ navToggle.focus() // for accessibility
+ })
+ } else if (visibility == 'true') {
+ $('.header').append(primaryNav)
+ $('.nav-buttons').append(navToggle)
- primaryNav.setAttribute("data-opened", "false");
- navToggle.setAttribute("aria-expanded", "false");
- navButtons.style.display = "";
+ primaryNav.setAttribute('data-opened', 'false')
+ navToggle.setAttribute('aria-expanded', 'false')
+ navButtons.style.display = ''
- navToggle.classList.remove("cross");
+ navToggle.classList.remove('cross')
// slideOutLeft, zoomOutDown
- animateCSS(".nav", "flipOutY").then((message) => {
+ animateCSS('.nav', 'flipOutY').then((message) => {
// Do something after the animation
- primaryNav.style.display = "none";
- });
+ primaryNav.style.display = 'none'
+ })
}
- });
+ })
// theme toggler
- switchTheme(theme);
- themeToggle.addEventListener("click", () => {
+ switchTheme(theme)
+ themeToggle.addEventListener('click', () => {
// in the future I could implement not just dark mode
// buy more themes.
- if (document.body.classList.contains("theme-dark")) {
- switchTheme("theme-light");
+ if (document.body.classList.contains('theme-dark')) {
+ switchTheme('theme-light')
} else {
- switchTheme("theme-dark");
+ switchTheme('theme-dark')
}
- });
+ })
// read more button. Note! Arrow functions do not have a "this" context, so avoid
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#the_value_of_this_within_the_handler
- if ($(".read-more-btn")) {
- $(".read-more-btn").addEventListener("click", function (e) {
- let readMoreText = $(".read-more-text");
-
- if (false === readMoreText.classList.contains("read-more-text-active")) {
+ if ($('.read-more-btn')) {
+ $('.read-more-btn').addEventListener('click', function (e) {
+ let readMoreText = $('.read-more-text')
+
+ if (
+ false ===
+ readMoreText.classList.contains('read-more-text-active')
+ ) {
// show text
// first get the height of the hidden text,
// it must be visible for the browser first in order to have a height
// https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight
- readMoreText.classList.add("read-more-text-active");
- readMoreText.style.height = "auto";
- let height = readMoreText.clientHeight + "px";
+ readMoreText.classList.add('read-more-text-active')
+ readMoreText.style.height = 'auto'
+ let height = readMoreText.clientHeight + 'px'
// reset the height and animate, via configured css styles
- readMoreText.style.height = "0px";
+ readMoreText.style.height = '0px'
setTimeout(function () {
- readMoreText.style.height = height;
- }, 0);
+ readMoreText.style.height = height
+ }, 0)
// smooth scroll to this anchor
- goToHashed("#more");
+ goToHashed('#more')
// change button text and icon
- this.querySelector("svg:nth-child(1)").classList.add("d-none");
- this.querySelector("svg:nth-child(2)").classList.remove("d-none");
- this.querySelector("span").textContent = "Read less";
+ this.querySelector('svg:nth-child(1)').classList.add(
+ 'd-none'
+ )
+ this.querySelector('svg:nth-child(2)').classList.remove(
+ 'd-none'
+ )
+ this.querySelector('span').textContent = 'Read less'
} else {
// hide text
// smart use of: https://developer.mozilla.org/en-US/docs/Web/API/Element/transitionend_event
// thanks to Ciprian Popescu, https://github.com/wolffe
- readMoreText.style.height = "0px";
+ readMoreText.style.height = '0px'
readMoreText.addEventListener(
- "transitionend",
+ 'transitionend',
function () {
- readMoreText.classList.remove("read-more-text-active");
+ readMoreText.classList.remove(
+ 'read-more-text-active'
+ )
},
{
once: true,
}
- );
+ )
// smooth scroll to this anchor
- goToHashed("#lets-work-together", "20px");
+ goToHashed('#lets-work-together', '20px')
// change button text and icon back to read-more
- this.querySelector("svg:nth-child(1)").classList.remove("d-none");
- this.querySelector("svg:nth-child(2)").classList.add("d-none");
- this.querySelector("span").textContent = "Read more";
+ this.querySelector('svg:nth-child(1)').classList.remove(
+ 'd-none'
+ )
+ this.querySelector('svg:nth-child(2)').classList.add(
+ 'd-none'
+ )
+ this.querySelector('span').textContent = 'Read more'
}
- e.preventDefault();
- });
+ e.preventDefault()
+ })
}
// add hashing links to headings for deep linking
- const articleHeadings = $(".article h2, .article .h2, .deeplinked h2", "all");
+ const articleHeadings = $(
+ '.article h2, .article .h2, .deeplinked h2',
+ 'all'
+ )
articleHeadings &&
articleHeadings.forEach((heading) => {
- if (heading.getAttribute("id")) {
+ if (heading.getAttribute('id')) {
heading.innerHTML =
- `# ` + heading.innerHTML;
+ }' class='heading-hash'># ` + heading.innerHTML
}
- });
+ })
// anchor internal links smooth-scrolling
- const anchors = $('a[href*="#"]', "all");
+ const anchors = $('a[href*="#"]', 'all')
anchors &&
anchors.forEach((anchor) => {
- anchor.addEventListener("click", function (e) {
- e.preventDefault();
+ anchor.addEventListener('click', function (e) {
+ e.preventDefault()
// console.log("Hashing link");
- let hashValue = this.getAttribute("href");
- if (hashValue == "#") return;
- const goToHash = $(hashValue);
-
- goToHash.style.scrollMarginTop = "10px";
- goToHash.scrollIntoView({ behavior: "smooth", block: "start" });
-
- window.history && history.replaceState(undefined, undefined, this.getAttribute("href"));
- });
- });
+ let hashValue = this.getAttribute('href')
+ if (hashValue == '#') return
+ const goToHash = $(hashValue)
+
+ goToHash.style.scrollMarginTop = '10px'
+ goToHash.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start',
+ })
+
+ window.history &&
+ history.replaceState(
+ undefined,
+ undefined,
+ this.getAttribute('href')
+ )
+ })
+ })
// process on-page-load hashes (go to anchor, smoothly)
- goToHashed();
+ goToHashed()
// process manual hash changes, also smoothly
window.addEventListener(
- "hashchange",
+ 'hashchange',
(e) => {
- e.preventDefault();
- goToHashed();
+ e.preventDefault()
+ goToHashed()
},
false
- );
+ )
},
false
-);
+)
// functions
-const animateProfileImage = () => animateCSS(profileImage, "rubberBand");
+const animateProfileImage = () => animateCSS(profileImage, 'rubberBand')
const switchTheme = (themeClassName) => {
// Credit to https://thegermancoder.com/2018/10/04/how-to-remove-classes-by-prefix-in-vanilla-javascript/
- let prefix = "theme-";
- let regx = new RegExp("\\b" + prefix + "[^ ]*[ ]?\\b", "g");
- document.body.className = document.body.className.replace(regx, "");
+ let prefix = 'theme-'
+ let regx = new RegExp('\\b' + prefix + '[^ ]*[ ]?\\b', 'g')
+ document.body.className = document.body.className.replace(regx, '')
- document.body.classList.add(themeClassName);
- theme = localStorage.setItem("theme", themeClassName);
-};
+ document.body.classList.add(themeClassName)
+ theme = localStorage.setItem('theme', themeClassName)
+}
// function to user the animate.css lib from js
-const animateCSS = (element, animation, prefix = "animate__") =>
+const animateCSS = (element, animation, prefix = 'animate__') =>
// We create a Promise and return it
new Promise((resolve, reject) => {
- const animationName = `${prefix}${animation}`;
- if (typeof element == "string") element = $(element);
+ const animationName = `${prefix}${animation}`
+ if (typeof element == 'string') element = $(element)
- element.classList.add(`${prefix}animated`, animationName);
+ element.classList.add(`${prefix}animated`, animationName)
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event) {
- event.stopPropagation();
- element.classList.remove(`${prefix}animated`, animationName);
- resolve("Animation ended");
+ event.stopPropagation()
+ element.classList.remove(`${prefix}animated`, animationName)
+ resolve('Animation ended')
}
- element.addEventListener("animationend", handleAnimationEnd, {
+ element.addEventListener('animationend', handleAnimationEnd, {
once: true,
- });
- });
+ })
+ })
const displayGpx = function (elt, filePath) {
- if (!elt) return;
+ if (!elt) return
- var url = filePath || elt.getAttribute("data-gpx-source");
- var mapid = elt.getAttribute("data-map-target");
- if (!url || !mapid) return;
+ var url = filePath || elt.getAttribute('data-gpx-source')
+ var mapid = elt.getAttribute('data-map-target')
+ if (!url || !mapid) return
function _t(t) {
- return elt.getElementsByTagName(t)[0];
+ return elt.getElementsByTagName(t)[0]
}
function _c(c) {
- return elt.getElementsByClassName(c)[0];
+ return elt.getElementsByClassName(c)[0]
}
- $("#" + mapid).remove();
- let newMapDiv = document.createElement("div");
- newMapDiv.id = mapid;
- newMapDiv.classList.add("map");
- $("#biking-map").append(newMapDiv);
+ $('#' + mapid).remove()
+ let newMapDiv = document.createElement('div')
+ newMapDiv.id = mapid
+ newMapDiv.classList.add('map')
+ $('#biking-map').append(newMapDiv)
- var map = L.map(mapid);
+ var map = L.map(mapid)
- L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
- attribution: 'Map data © OpenStreetMap',
- }).addTo(map);
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ attribution:
+ 'Map data © OpenStreetMap',
+ }).addTo(map)
- var control = L.control.layers(null, null).addTo(map);
+ var control = L.control.layers(null, null).addTo(map)
new L.GPX(url, {
async: true,
marker_options: {
- startIconUrl: "/assets/images/pin-icon-start.png",
- endIconUrl: "/assets/images/pin-icon-end.png",
- shadowUrl: "/assets/images/pin-shadow.png",
+ startIconUrl: '/assets/images/pin-icon-start.png',
+ endIconUrl: '/assets/images/pin-icon-end.png',
+ shadowUrl: '/assets/images/pin-shadow.png',
},
})
- .on("loaded", function (e) {
- var gpx = e.target;
- map.fitBounds(gpx.getBounds());
- control.addOverlay(gpx, gpx.get_name());
-
- _t("h3").textContent = gpx.get_name();
- _c("start").textContent =
- gpx.get_start_time().toDateString() + ", " + gpx.get_start_time().toLocaleTimeString();
- _c("distance").textContent = (gpx.get_distance() / 1000).toFixed(2);
- _c("duration").textContent = gpx.get_duration_string(gpx.get_moving_time());
+ .on('loaded', function (e) {
+ var gpx = e.target
+ map.fitBounds(gpx.getBounds())
+ control.addOverlay(gpx, gpx.get_name())
+
+ _t('h3').textContent = gpx.get_name()
+ _c('start').textContent =
+ gpx.get_start_time().toDateString() +
+ ', ' +
+ gpx.get_start_time().toLocaleTimeString()
+ _c('distance').textContent = (gpx.get_distance() / 1000).toFixed(2)
+ _c('duration').textContent = gpx.get_duration_string(
+ gpx.get_moving_time()
+ )
// _c('pace').textContent = gpx.get_duration_string(gpx.get_moving_pace_imp(), true);
- _c("pace").textContent = gpx.get_duration_string(gpx.get_moving_pace(), true);
+ _c('pace').textContent = gpx.get_duration_string(
+ gpx.get_moving_pace(),
+ true
+ )
// _c('avghr').textContent = gpx.get_average_hr();
// _c('elevation-gain').textContent = gpx.to_ft(gpx.get_elevation_gain()).toFixed(0);
@@ -309,9 +347,15 @@ const displayGpx = function (elt, filePath) {
// _c('elevation-net').textContent = gpx.to_ft(gpx.get_elevation_gain()
// - gpx.get_elevation_loss()).toFixed(0);
- _c("elevation-gain").textContent = gpx.get_elevation_gain().toFixed(0);
- _c("elevation-loss").textContent = gpx.get_elevation_loss().toFixed(0);
- _c("elevation-net").textContent = (gpx.get_elevation_gain() - gpx.get_elevation_loss()).toFixed(0);
+ _c('elevation-gain').textContent = gpx
+ .get_elevation_gain()
+ .toFixed(0)
+ _c('elevation-loss').textContent = gpx
+ .get_elevation_loss()
+ .toFixed(0)
+ _c('elevation-net').textContent = (
+ gpx.get_elevation_gain() - gpx.get_elevation_loss()
+ ).toFixed(0)
})
- .addTo(map);
-};
+ .addTo(map)
+}