240 lines
6.2 KiB
JavaScript
240 lines
6.2 KiB
JavaScript
|
(function() {
|
||
|
"use strict";
|
||
|
|
||
|
/**
|
||
|
* Easy selector helper function
|
||
|
*/
|
||
|
const select = (el, all = false) => {
|
||
|
el = el.trim()
|
||
|
if (all) {
|
||
|
return [...document.querySelectorAll(el)]
|
||
|
} else {
|
||
|
return document.querySelector(el)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Easy event listener function
|
||
|
*/
|
||
|
const on = (type, el, listener, all = false) => {
|
||
|
let selectEl = select(el, all)
|
||
|
if (selectEl) {
|
||
|
if (all) {
|
||
|
selectEl.forEach(e => e.addEventListener(type, listener))
|
||
|
} else {
|
||
|
selectEl.addEventListener(type, listener)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Easy on scroll event listener
|
||
|
*/
|
||
|
const onscroll = (el, listener) => {
|
||
|
el.addEventListener('scroll', listener)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Navbar links active state on scroll
|
||
|
*/
|
||
|
let navbarlinks = select('#navbar .scrollto', true)
|
||
|
const navbarlinksActive = () => {
|
||
|
let position = window.scrollY + 200
|
||
|
navbarlinks.forEach(navbarlink => {
|
||
|
if (!navbarlink.hash) return
|
||
|
let section = select(navbarlink.hash)
|
||
|
if (!section) return
|
||
|
if (position >= section.offsetTop && position <= (section.offsetTop + section.offsetHeight)) {
|
||
|
navbarlink.classList.add('active')
|
||
|
} else {
|
||
|
navbarlink.classList.remove('active')
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
window.addEventListener('load', navbarlinksActive)
|
||
|
onscroll(document, navbarlinksActive)
|
||
|
|
||
|
/**
|
||
|
* Scrolls to an element with header offset
|
||
|
*/
|
||
|
const scrollto = (el) => {
|
||
|
let header = select('#header')
|
||
|
let offset = header.offsetHeight
|
||
|
|
||
|
let elementPos = select(el).offsetTop
|
||
|
window.scrollTo({
|
||
|
top: elementPos - offset,
|
||
|
behavior: 'smooth'
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Header fixed top on scroll
|
||
|
*/
|
||
|
let selectHeader = select('#header')
|
||
|
if (selectHeader) {
|
||
|
let headerOffset = selectHeader.offsetTop
|
||
|
let nextElement = selectHeader.nextElementSibling
|
||
|
const headerFixed = () => {
|
||
|
if ((headerOffset - window.scrollY) <= 0) {
|
||
|
selectHeader.classList.add('fixed-top')
|
||
|
nextElement.classList.add('scrolled-offset')
|
||
|
} else {
|
||
|
selectHeader.classList.remove('fixed-top')
|
||
|
nextElement.classList.remove('scrolled-offset')
|
||
|
}
|
||
|
}
|
||
|
window.addEventListener('load', headerFixed)
|
||
|
onscroll(document, headerFixed)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Hero carousel indicators
|
||
|
*/
|
||
|
let heroCarouselIndicators = select("#hero-carousel-indicators")
|
||
|
let heroCarouselItems = select('#heroCarousel .carousel-item', true)
|
||
|
|
||
|
heroCarouselItems.forEach((item, index) => {
|
||
|
(index === 0) ?
|
||
|
heroCarouselIndicators.innerHTML += "<li data-bs-target='#heroCarousel' data-bs-slide-to='" + index + "' class='active'></li>":
|
||
|
heroCarouselIndicators.innerHTML += "<li data-bs-target='#heroCarousel' data-bs-slide-to='" + index + "'></li>"
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Back to top button
|
||
|
*/
|
||
|
let backtotop = select('.back-to-top')
|
||
|
if (backtotop) {
|
||
|
const toggleBacktotop = () => {
|
||
|
if (window.scrollY > 100) {
|
||
|
backtotop.classList.add('active')
|
||
|
} else {
|
||
|
backtotop.classList.remove('active')
|
||
|
}
|
||
|
}
|
||
|
window.addEventListener('load', toggleBacktotop)
|
||
|
onscroll(document, toggleBacktotop)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mobile nav toggle
|
||
|
*/
|
||
|
on('click', '.mobile-nav-toggle', function(e) {
|
||
|
select('#navbar').classList.toggle('navbar-mobile')
|
||
|
this.classList.toggle('bi-list')
|
||
|
this.classList.toggle('bi-x')
|
||
|
})
|
||
|
|
||
|
/**
|
||
|
* Mobile nav dropdowns activate
|
||
|
*/
|
||
|
on('click', '.navbar .dropdown > a', function(e) {
|
||
|
if (select('#navbar').classList.contains('navbar-mobile')) {
|
||
|
e.preventDefault()
|
||
|
this.nextElementSibling.classList.toggle('dropdown-active')
|
||
|
}
|
||
|
}, true)
|
||
|
|
||
|
/**
|
||
|
* Scrool with ofset on links with a class name .scrollto
|
||
|
*/
|
||
|
on('click', '.scrollto', function(e) {
|
||
|
if (select(this.hash)) {
|
||
|
e.preventDefault()
|
||
|
|
||
|
let navbar = select('#navbar')
|
||
|
if (navbar.classList.contains('navbar-mobile')) {
|
||
|
navbar.classList.remove('navbar-mobile')
|
||
|
let navbarToggle = select('.mobile-nav-toggle')
|
||
|
navbarToggle.classList.toggle('bi-list')
|
||
|
navbarToggle.classList.toggle('bi-x')
|
||
|
}
|
||
|
scrollto(this.hash)
|
||
|
}
|
||
|
}, true)
|
||
|
|
||
|
/**
|
||
|
* Scroll with ofset on page load with hash links in the url
|
||
|
*/
|
||
|
window.addEventListener('load', () => {
|
||
|
if (window.location.hash) {
|
||
|
if (select(window.location.hash)) {
|
||
|
scrollto(window.location.hash)
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Skills animation
|
||
|
*/
|
||
|
let skilsContent = select('.skills-content');
|
||
|
if (skilsContent) {
|
||
|
new Waypoint({
|
||
|
element: skilsContent,
|
||
|
offset: '80%',
|
||
|
handler: function(direction) {
|
||
|
let progress = select('.progress .progress-bar', true);
|
||
|
progress.forEach((el) => {
|
||
|
el.style.width = el.getAttribute('aria-valuenow') + '%'
|
||
|
});
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Porfolio isotope and filter
|
||
|
*/
|
||
|
window.addEventListener('load', () => {
|
||
|
let portfolioContainer = select('.portfolio-container');
|
||
|
if (portfolioContainer) {
|
||
|
let portfolioIsotope = new Isotope(portfolioContainer, {
|
||
|
itemSelector: '.portfolio-item',
|
||
|
layoutMode: 'fitRows'
|
||
|
});
|
||
|
|
||
|
let portfolioFilters = select('#portfolio-flters li', true);
|
||
|
|
||
|
on('click', '#portfolio-flters li', function(e) {
|
||
|
e.preventDefault();
|
||
|
portfolioFilters.forEach(function(el) {
|
||
|
el.classList.remove('filter-active');
|
||
|
});
|
||
|
this.classList.add('filter-active');
|
||
|
|
||
|
portfolioIsotope.arrange({
|
||
|
filter: this.getAttribute('data-filter')
|
||
|
});
|
||
|
}, true);
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Initiate portfolio lightbox
|
||
|
*/
|
||
|
const portfolioLightbox = GLightbox({
|
||
|
selector: '.portfolio-lightbox'
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Portfolio details slider
|
||
|
*/
|
||
|
new Swiper('.portfolio-details-slider', {
|
||
|
speed: 400,
|
||
|
autoplay: {
|
||
|
delay: 5000,
|
||
|
disableOnInteraction: false
|
||
|
},
|
||
|
pagination: {
|
||
|
el: '.swiper-pagination',
|
||
|
type: 'bullets',
|
||
|
clickable: true
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Initiate Pure Counter
|
||
|
*/
|
||
|
new PureCounter();
|
||
|
|
||
|
})()
|