feat: build website
This commit is contained in:
45
static/js/contact.js
Normal file
45
static/js/contact.js
Normal file
@@ -0,0 +1,45 @@
|
||||
async function handleFormspreeSubmit(event) {
|
||||
event.preventDefault();
|
||||
var form = document.getElementById("contact-form");
|
||||
var data = new FormData(event.target);
|
||||
fetch(event.target.action, {
|
||||
method: form.method,
|
||||
body: data,
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
contactAlert("success", "Thanks for your submission!");
|
||||
form.reset();
|
||||
} else {
|
||||
response.json().then((data) => {
|
||||
var errMessage = data.errors;
|
||||
for (var i = 0; i < errMessage.length; i++) {
|
||||
contactAlert("danger", errMessage[i].message);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
contactAlert("danger", "Oops! There was a problem submitting your form");
|
||||
});
|
||||
}
|
||||
|
||||
function contactAlert(type, message) {
|
||||
var contactFormStatus = document.getElementById("contact-form-status");
|
||||
var alert = `<div class="alert alert-${type} d-flex align-items-center" role="alert">
|
||||
<svg class="bi flex-shrink-0 me-2" role="img" aria-label="Success:">
|
||||
<use xlink:href="#check-circle-fill" />
|
||||
</svg>
|
||||
<div>${message}</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>`;
|
||||
contactFormStatus.innerHTML = alert;
|
||||
|
||||
// Remove alert after 3 seconds
|
||||
setTimeout(function () {
|
||||
contactFormStatus.innerHTML = "";
|
||||
}, 3000);
|
||||
}
|
||||
10
static/js/readingTime.js
Normal file
10
static/js/readingTime.js
Normal file
@@ -0,0 +1,10 @@
|
||||
function readingTime() {
|
||||
const text = document.querySelector("article").innerText;
|
||||
const wpm = 225;
|
||||
const words = text.trim().split(/\s+/).length;
|
||||
const time = Math.ceil(words / wpm);
|
||||
|
||||
const timeElement = document.querySelector("span#readingTime");
|
||||
timeElement.innerHTML = "<small> | </small>" + time + timeElement.innerHTML;
|
||||
}
|
||||
readingTime();
|
||||
12
static/js/scrollProgressBar.js
Normal file
12
static/js/scrollProgressBar.js
Normal file
@@ -0,0 +1,12 @@
|
||||
function getScrollPercent() {
|
||||
const totalHeight = document.body.scrollHeight - window.innerHeight;
|
||||
const scrolled = window.scrollY;
|
||||
return (scrolled / totalHeight) * 100;
|
||||
}
|
||||
const scrollProgressBar = document.getElementById("scroll-progress-bar");
|
||||
|
||||
document.onscroll = function () {
|
||||
var scrollPercent = Math.round(getScrollPercent());
|
||||
scrollProgressBar.style.width = scrollPercent + "%";
|
||||
scrollProgressBar.ariaValueNow = scrollPercent;
|
||||
};
|
||||
138
static/js/search.js
Normal file
138
static/js/search.js
Normal file
@@ -0,0 +1,138 @@
|
||||
async function searchOnChange(evt) {
|
||||
let searchQuery = evt.target.value;
|
||||
var inputEle = document.querySelectorAll("input#search");
|
||||
inputEle.forEach((element) => {
|
||||
element.value = searchQuery;
|
||||
});
|
||||
|
||||
if (searchQuery !== "") {
|
||||
if (!window.searchJson) {
|
||||
window.searchJson = await fetch("/index.json").then((res) => res.json());
|
||||
}
|
||||
|
||||
let searchResults = searchJson.filter((item) => {
|
||||
let res = false;
|
||||
if (item.title && item.description && item.content) {
|
||||
res =
|
||||
item.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
item.description.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
item.content.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
} else if (item.title && item.description) {
|
||||
res =
|
||||
item.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
item.description.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
} else if (item.title && item.content) {
|
||||
res =
|
||||
item.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
item.content.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
} else if (item.description && item.content) {
|
||||
res =
|
||||
item.description.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
item.content.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
} else if (item.title) {
|
||||
res = item.title.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
} else if (item.description) {
|
||||
res = item.description
|
||||
.toLowerCase()
|
||||
.includes(searchQuery.toLowerCase());
|
||||
} else if (item.content) {
|
||||
res = item.content.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
}
|
||||
return res;
|
||||
});
|
||||
if (searchResults.length > 0) {
|
||||
let searchResultsHtml = "";
|
||||
searchResults.map((item) => {
|
||||
searchResultsHtml += `<div class="card">
|
||||
<a href="${item.permalink}">
|
||||
<div class="p-3">
|
||||
<h5>${item.title}</h5>
|
||||
<div>${item.description}</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>`;
|
||||
});
|
||||
document.getElementById("search-results").innerHTML = searchResultsHtml;
|
||||
} else {
|
||||
let searchResultsHtml = `<p class="text-center py-3">No results found for "${searchQuery}"</p>`;
|
||||
document.getElementById("search-results").innerHTML = searchResultsHtml;
|
||||
}
|
||||
alignSearchContent();
|
||||
document.getElementById("search-content").style.display = "block";
|
||||
} else {
|
||||
document.getElementById("search-content").style.display = "none";
|
||||
document.getElementById("search-results").innerHTML = "";
|
||||
}
|
||||
}
|
||||
|
||||
function alignSearchContent() {
|
||||
const searchButtonEle = document.querySelectorAll("#search");
|
||||
// check if search value is not empty
|
||||
for (let i = 0; i < searchButtonEle.length; i++) {
|
||||
if (searchButtonEle[i].value !== "") {
|
||||
let searchButtonPosition;
|
||||
if (window.innerWidth > 768) {
|
||||
searchButtonPosition = searchButtonEle[0].getBoundingClientRect();
|
||||
document.getElementById("search-content").style.width = "500px";
|
||||
} else {
|
||||
var navbarCollapse = document.querySelector("#navbarContent");
|
||||
navbarCollapse.classList.add("show");
|
||||
searchButtonPosition = searchButtonEle[1].getBoundingClientRect();
|
||||
document.getElementById("search-content").style.width = "300px";
|
||||
}
|
||||
|
||||
document.getElementById("search-content").style.top =
|
||||
searchButtonPosition.top + 50 + "px";
|
||||
document.getElementById("search-content").style.left =
|
||||
searchButtonPosition.left + "px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetSearch(e) {
|
||||
if (
|
||||
e.keyCode === 27 ||
|
||||
(e.target.id !== "search" &&
|
||||
e.target.closest("section#search-content") === null)
|
||||
) {
|
||||
if (document.getElementById("search-results").innerHTML !== "") {
|
||||
document.getElementById("search-content").style.display = "none";
|
||||
document.getElementById("search-results").innerHTML = "";
|
||||
var inputEle = document.querySelectorAll("input#search");
|
||||
inputEle.forEach((element) => {
|
||||
element.value = "";
|
||||
element.blur();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.onkeyup = function () {
|
||||
switch (event.keyCode) {
|
||||
// ESC
|
||||
case 27:
|
||||
resetSearch(event);
|
||||
break;
|
||||
|
||||
// ctrl + k
|
||||
case 75:
|
||||
if (event.ctrlKey) {
|
||||
document.getElementById("search").focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", function (e) {
|
||||
if (e.keyCode === 75 && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// Close search on click outside and on resize
|
||||
document.addEventListener("click", function (e) {
|
||||
resetSearch(e);
|
||||
});
|
||||
window.addEventListener("resize", function (e) {
|
||||
alignSearchContent();
|
||||
});
|
||||
Reference in New Issue
Block a user