// scrolling effect const scrollLimit = 150; // array with texts to type in typewriter var dataText = ["full stack developer", "web designer", "student", "gamer", "drummer"]; window.onscroll = () => { // check if scrolled past limit if so add scrolled class to change background of nav if (document.body.scrollTop >= scrollLimit || document.documentElement.scrollTop >= scrollLimit) { document.querySelector("nav").classList.add("scrolled"); } else { document.querySelector("nav").classList.remove("scrolled"); } let current = ""; //id of current section scrolled to, set to "" if at top // go through all sections and find current section id scrolled to document.querySelectorAll("section").forEach((section) => { const sectionTop = section.offsetTop; if (window.pageYOffset >= sectionTop - 60) { current = section.getAttribute("id"); } }); // go through all nav links, remove active class and add it to the link whose href matches the current id scrolled // to document.querySelectorAll("nav ul li a").forEach((a) => { a.classList.remove("active"); if (a.href.includes(current) && current !== "") { a.classList.add("active"); } else if (current === "") { document.querySelector("nav ul li a").classList.add("active"); // at the top } }); }; // typewriter effect /** * typeWriter function * type one character at a time in the typewriter * keeps calling itself until the text is finished * @param {string} text text to type * @param {number} i current index at which the next character should be typed * @param {function} fnCallback function to call back in this case the StartTextAnimation function */ function typeWriter(text, i, fnCallback) { // check if text isn't finished yet if (i < (text.length)) { // add next character to h1 document.querySelector("header div h1").innerHTML = text.substring(0, i + 1) + "_"; // wait for a while and call this function again for next character setTimeout(function () { typeWriter(text, i + 1, fnCallback) }, 100); } // text finished, call callback if there is a callback function else if (typeof fnCallback == "function") { // call callback after timeout setTimeout(fnCallback, 700); } } /** * StartTextAnimation function * start a typewriter animation for a text in the dataText array * @param {number} i current index at which text should be typed next */ function StartTextAnimation(i) { if (typeof dataText[i] === "undefined") { setTimeout(function () { StartTextAnimation(0); }, 1500); } else if (i < dataText[i].length) { // text exists! start typewriter animation typeWriter(dataText[i], 0, function () { // after callback (and whole text has been animated), start next text setTimeout(StartTextAnimation, 1500, i + 1); }); } } // cv timeline data /** * getTimelineData function * Gets the timeline data from backend route and appends the data on to the timeline. */ function getTimelineData() { fetch("/api/timelineData/edu").then(res => { res.json().then(json => { if (res.ok) { json.forEach(item => { let timelineItem = document.createElement("div") timelineItem.classList.add("timelineItem"); timelineItem.innerHTML = `

${item["startPeriod"]} - ${item["endPeriod"]}

Grade: ${item["grade"]}

${item["course"]}

`; document.getElementById("edu").appendChild(timelineItem); }); } }) }); fetch("/api/timelineData/work").then(res => { res.json().then(json => { if (res.ok) { json.forEach(item => { let timelineItem = document.createElement("div") timelineItem.classList.add("timelineItem"); timelineItem.innerHTML = `

${item["startPeriod"]} - ${item["endPeriod"]}

${item["companyName"]} - ${item["area"]}

${item["title"]}

`; document.getElementById("work").appendChild(timelineItem); }) } }) }) } /** * getProjectData function * Gets the project data from the backend route and appends the data on to the timeline. */ function getProjectData() { fetch("/api/projectData").then(res => { res.json().then(json => { if (res.ok) { json.forEach(item => { if (item["isMainProject"] === "1") { document.getElementById("mainProj").innerHTML = `

${item["title"]}

${item["information"]}

`; return null; } document.querySelector("#otherProj div").innerHTML += `

${item["information"]}

View Project ${(item["githubLink"] === "N/A") ? "disabled=\"disabled\"" : ""}Github
`; }) } }) }) } document.addEventListener('DOMContentLoaded', () => { // start the text animation StartTextAnimation(0); // get timeline data and add it to the timeline getTimelineData(); // get projectData getProjectData(); }); // contact form document.querySelector("#contactForm").addEventListener("submit", e => { e.preventDefault(); let contactData = new FormData(); contactData.append("fName", document.querySelector("#fName").value); contactData.append("lName", document.querySelector("#lName").value); contactData.append("email", document.querySelector("#email").value); contactData.append("subject", document.querySelector("#subject").value); contactData.append("message", document.querySelector("#message").value); if (document.querySelector("#fName").value.length == 0) { document.querySelector("#fName").classList.add("invalid"); // please fill out all the fields return; } else { document.querySelector("#fName").classList.remove("invalid"); } if (document.querySelector("#lName").value.length == 0) { document.querySelector("#lName").classList.add("invalid"); // please fill out all the fields return; } else { document.querySelector("#lName").classList.remove("invalid"); } if (document.querySelector("#email").value.length == 0) { document.querySelector("#email").classList.add("invalid"); // please fill out all the fields return; } else { document.querySelector("#email").classList.remove("invalid"); } if (document.querySelector("#subject").value.length == 0) { document.querySelector("#subject").classList.add("invalid"); // please fill out all the fields return; } else { document.querySelector("#subject").classList.remove("invalid"); } if (document.querySelector("#message").value.length == 0) { document.querySelector("#message").classList.add("invalid"); // please fill out all the fields return; } else { document.querySelector("#message").classList.remove("invalid"); } fetch("/api/contact", { method: "POST", body: contactData }).then(res => { if(res.ok) { // show message box } }); });