RakeshPortfolio / script.js
SRVCP's picture
Upload 5 files
e91c622 verified
// Portfolio Website JavaScript
// Interactive functionality for navigation, theme toggle, and user experience
(function() {
'use strict';
// DOM Elements
const themeToggle = document.getElementById('themeToggle');
const navToggle = document.querySelector('.nav-toggle');
const navLinks = document.querySelector('.nav-links');
const header = document.querySelector('.site-header');
const resumeBtn = document.getElementById('resumeBtn');
// Theme Management
class ThemeManager {
constructor() {
this.currentTheme = localStorage.getItem('theme') || 'light';
this.init();
}
init() {
this.applyTheme(this.currentTheme);
this.updateThemeIcon();
if (themeToggle) {
themeToggle.addEventListener('click', () => this.toggleTheme());
}
}
toggleTheme() {
this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';
this.applyTheme(this.currentTheme);
this.updateThemeIcon();
localStorage.setItem('theme', this.currentTheme);
}
applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
}
updateThemeIcon() {
if (themeToggle) {
themeToggle.innerHTML = this.currentTheme === 'light' ? '🌙' : '☀️';
themeToggle.setAttribute('aria-label',
`Switch to ${this.currentTheme === 'light' ? 'dark' : 'light'} mode`);
}
}
}
// Navigation Management
class NavigationManager {
constructor() {
this.isMenuOpen = false;
this.init();
}
init() {
// Mobile menu toggle
if (navToggle && navLinks) {
navToggle.addEventListener('click', () => this.toggleMobileMenu());
}
// Close mobile menu when clicking on links
if (navLinks) {
navLinks.addEventListener('click', (e) => {
if (e.target.tagName === 'A') {
this.closeMobileMenu();
}
});
}
// Close mobile menu when clicking outside
document.addEventListener('click', (e) => {
if (this.isMenuOpen && !e.target.closest('.nav')) {
this.closeMobileMenu();
}
});
// Smooth scrolling for anchor links
this.initSmoothScrolling();
// Header scroll effect
this.initHeaderScrollEffect();
}
toggleMobileMenu() {
this.isMenuOpen = !this.isMenuOpen;
navLinks.classList.toggle('active', this.isMenuOpen);
navToggle.setAttribute('aria-expanded', this.isMenuOpen.toString());
navToggle.innerHTML = this.isMenuOpen ? '✕' : '☰';
}
closeMobileMenu() {
this.isMenuOpen = false;
navLinks.classList.remove('active');
navToggle.setAttribute('aria-expanded', 'false');
navToggle.innerHTML = '☰';
}
initSmoothScrolling() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', (e) => {
const href = anchor.getAttribute('href');
if (href === '#' || href === '#top') {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
return;
}
const target = document.querySelector(href);
if (target) {
e.preventDefault();
const headerHeight = header ? header.offsetHeight : 0;
const targetPosition = target.offsetTop - headerHeight - 20;
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
}
});
});
}
initHeaderScrollEffect() {
if (!header) return;
let lastScrollY = window.scrollY;
let ticking = false;
const updateHeader = () => {
const scrollY = window.scrollY;
if (scrollY > 100) {
header.style.background = 'rgba(255, 255, 255, 0.95)';
header.style.backdropFilter = 'blur(10px)';
} else {
header.style.background = '';
header.style.backdropFilter = '';
}
lastScrollY = scrollY;
ticking = false;
};
const requestTick = () => {
if (!ticking) {
requestAnimationFrame(updateHeader);
ticking = true;
}
};
window.addEventListener('scroll', requestTick, { passive: true });
}
}
// Resume Download Manager
class ResumeManager {
constructor() {
this.init();
}
init() {
if (resumeBtn) {
resumeBtn.addEventListener('click', (e) => this.handleResumeDownload(e));
}
}
handleResumeDownload(e) {
e.preventDefault();
// Show loading state
const originalText = resumeBtn.innerHTML;
resumeBtn.innerHTML = '📄 Downloading...';
resumeBtn.classList.add('loading');
// Create download link
const link = document.createElement('a');
link.href = 'Rakesh Resume.pdf';
link.download = 'Rakesh_Kumar_Resume.pdf';
link.style.display = 'none';
document.body.appendChild(link);
// Trigger download
try {
link.click();
// Track download (if analytics is available)
if (typeof gtag !== 'undefined') {
gtag('event', 'download', {
'event_category': 'Resume',
'event_label': 'PDF Download'
});
}
// Show success message
setTimeout(() => {
resumeBtn.innerHTML = '✅ Downloaded!';
setTimeout(() => {
resumeBtn.innerHTML = originalText;
resumeBtn.classList.remove('loading');
}, 2000);
}, 500);
} catch (error) {
console.error('Download failed:', error);
resumeBtn.innerHTML = '❌ Download Failed';
setTimeout(() => {
resumeBtn.innerHTML = originalText;
resumeBtn.classList.remove('loading');
}, 2000);
} finally {
document.body.removeChild(link);
}
}
}
// Animation and Intersection Observer
class AnimationManager {
constructor() {
this.init();
}
init() {
// Intersection Observer for fade-in animations
if ('IntersectionObserver' in window) {
this.initScrollAnimations();
}
// Typing animation for hero subtitle
this.initTypingAnimation();
}
initScrollAnimations() {
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
}, observerOptions);
// Observe elements for animation
document.querySelectorAll('.card, .timeline li, .case').forEach(el => {
el.style.opacity = '0';
el.style.transform = 'translateY(30px)';
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
observer.observe(el);
});
}
initTypingAnimation() {
const subtitle = document.querySelector('.hero-subtitle');
if (!subtitle) return;
const text = subtitle.textContent;
subtitle.textContent = '';
subtitle.style.borderRight = '2px solid var(--accent-primary)';
let i = 0;
const typeWriter = () => {
if (i < text.length) {
subtitle.textContent += text.charAt(i);
i++;
setTimeout(typeWriter, 50);
} else {
// Remove cursor after typing is complete
setTimeout(() => {
subtitle.style.borderRight = 'none';
}, 1000);
}
};
// Start typing animation after a short delay
setTimeout(typeWriter, 1000);
}
}
// Utility Functions
class Utils {
static debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
static throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
static isElementInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
}
// Performance Monitoring
class PerformanceMonitor {
constructor() {
this.init();
}
init() {
// Log page load performance
window.addEventListener('load', () => {
if ('performance' in window) {
const perfData = performance.getEntriesByType('navigation')[0];
console.log('Page Load Time:', perfData.loadEventEnd - perfData.fetchStart, 'ms');
}
});
}
}
// Error Handling
class ErrorHandler {
constructor() {
this.init();
}
init() {
window.addEventListener('error', (e) => {
console.error('JavaScript Error:', e.error);
// Could send to analytics or error reporting service
});
window.addEventListener('unhandledrejection', (e) => {
console.error('Unhandled Promise Rejection:', e.reason);
// Could send to analytics or error reporting service
});
}
}
// Initialize Application
class App {
constructor() {
this.init();
}
init() {
// Wait for DOM to be ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.start());
} else {
this.start();
}
}
start() {
try {
// Initialize all managers
new ThemeManager();
new NavigationManager();
new ResumeManager();
new AnimationManager();
new PerformanceMonitor();
new ErrorHandler();
console.log('Portfolio website initialized successfully!');
} catch (error) {
console.error('Failed to initialize portfolio:', error);
}
}
}
// Start the application
new App();
})();
// Export for potential module use
if (typeof module !== 'undefined' && module.exports) {
module.exports = { App };
}