ultimate-jekyll-manager
Version:
Ultimate Jekyll dependency manager
147 lines (128 loc) • 4.55 kB
JavaScript
// Classy Theme JavaScript
// Modern interactions and animations
(function() {
'use strict';
// Navbar shrink on scroll
const navbar = document.querySelector('.navbar-modern');
if (navbar) {
window.addEventListener('scroll', function() {
if (window.scrollY > 50) {
navbar.classList.add('navbar-scrolled');
} else {
navbar.classList.remove('navbar-scrolled');
}
});
}
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
const href = this.getAttribute('href');
if (href !== '#' && href !== '#!') {
e.preventDefault();
const target = document.querySelector(href);
if (target) {
const navbarHeight = navbar ? navbar.offsetHeight : 0;
const targetPosition = target.getBoundingClientRect().top + window.pageYOffset - navbarHeight - 20;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
}
});
});
// Animate elements on scroll
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animated');
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Observe all elements with animate-in class
document.querySelectorAll('.animate-in').forEach(el => {
observer.observe(el);
});
// Add ripple effect to buttons
document.querySelectorAll('.btn').forEach(button => {
button.addEventListener('click', function(e) {
const ripple = document.createElement('span');
const rect = this.getBoundingClientRect();
const size = Math.max(rect.width, rect.height);
const x = e.clientX - rect.left - size / 2;
const y = e.clientY - rect.top - size / 2;
ripple.style.width = ripple.style.height = size + 'px';
ripple.style.left = x + 'px';
ripple.style.top = y + 'px';
ripple.classList.add('ripple');
this.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
});
});
// Parallax effect for hero sections
const heroSections = document.querySelectorAll('.hero-section');
if (heroSections.length > 0) {
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
heroSections.forEach(hero => {
const rate = scrolled * -0.5;
hero.style.transform = `translateY(${rate}px)`;
});
});
}
// Typing effect for headings with data-typing attribute
const typingElements = document.querySelectorAll('[data-typing]');
typingElements.forEach(element => {
const text = element.textContent;
element.textContent = '';
element.style.visibility = 'visible';
let charIndex = 0;
const typeInterval = setInterval(() => {
if (charIndex < text.length) {
element.textContent += text.charAt(charIndex);
charIndex++;
} else {
clearInterval(typeInterval);
}
}, 50);
});
// Enhanced tooltips initialization
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
tooltipTriggerList.forEach(tooltipTriggerEl => {
new bootstrap.Tooltip(tooltipTriggerEl, {
animation: true,
delay: { show: 100, hide: 100 }
});
});
// Form validation with modern styling
const forms = document.querySelectorAll('.needs-validation');
forms.forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
// Dynamic theme switching support
const themeToggle = document.querySelector('[data-bs-theme-toggle]');
if (themeToggle) {
themeToggle.addEventListener('click', () => {
const currentTheme = document.documentElement.getAttribute('data-bs-theme') || 'light';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-bs-theme', newTheme);
localStorage.setItem('theme', newTheme);
});
// Load saved theme
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-bs-theme', savedTheme);
}
})();