neonnexus-agency / script.js
thetwistedpixie's picture
Make it better
e68daf6 verified
// Theme Management
class ThemeManager {
constructor() {
this.themeToggle = document.getElementById('theme-toggle');
this.htmlElement = document.documentElement;
this.currentTheme = localStorage.getItem('theme') || 'dark';
this.init();
}
init() {
this.applyTheme(this.currentTheme);
this.themeToggle.addEventListener('click', () => this.toggleTheme());
}
applyTheme(theme) {
if (theme === 'light') {
this.htmlElement.classList.remove('dark-mode');
this.htmlElement.classList.add('light-mode');
document.body.classList.add('light-mode');
} else {
this.htmlElement.classList.remove('light-mode');
this.htmlElement.classList.add('dark-mode');
document.body.classList.remove('light-mode');
}
localStorage.setItem('theme', theme);
this.updateIcons(theme);
}
toggleTheme() {
const newTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
this.currentTheme = newTheme;
this.applyTheme(newTheme);
this.themeToggle.classList.add('animate-pulse-custom');
setTimeout(() => this.themeToggle.classList.remove('animate-pulse-custom'), 500);
}
updateIcons(theme) {
const darkIcon = this.themeToggle.querySelector('.dark-icon');
const lightIcon = this.themeToggle.querySelector('.light-icon');
if (theme === 'light') {
darkIcon.classList.remove('hidden');
lightIcon.classList.add('hidden');
} else {
darkIcon.classList.add('hidden');
lightIcon.classList.remove('hidden');
}
}
}
// Loading Screen
class LoadingManager {
constructor() {
this.loadingScreen = document.getElementById('loading-screen');
this.init();
}
init() {
window.addEventListener('load', () => {
setTimeout(() => {
this.loadingScreen.style.opacity = '0';
setTimeout(() => {
this.loadingScreen.style.display = 'none';
}, 500);
}, 1000);
});
}
}
// Smooth Scrolling
class SmoothScroll {
constructor() {
this.links = document.querySelectorAll('a[href^="#"]');
this.init();
}
init() {
this.links.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const targetId = link.getAttribute('href');
const targetSection = document.querySelector(targetId);
if (targetSection) {
targetSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
}
}
// Intersection Observer for Animations
class ScrollAnimations {
constructor() {
this.sections = document.querySelectorAll('section');
this.init();
}
init() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('section-visible');
entry.target.classList.remove('section-hidden');
}
});
}, {
threshold: 0.15,
rootMargin: '0px 0px -100px 0px'
});
this.sections.forEach(section => {
section.classList.add('section-hidden');
observer.observe(section);
});
}
}
// Contact Form Handler
class ContactForm {
constructor() {
this.form = document.getElementById('contact-form');
this.init();
}
init() {
if (this.form) {
this.form.addEventListener('submit', (e) => {
e.preventDefault();
this.handleSubmit();
});
}
}
async handleSubmit() {
const formData = new FormData(this.form);
const data = Object.fromEntries(formData);
// Show loading state
const submitButton = this.form.querySelector('button[type="submit"]');
const originalText = submitButton.innerHTML;
submitButton.innerHTML = '<i data-feather="loader" class="w-5 h-5 animate-spin inline-block"></i> Sending...';
feather.replace();
try {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
// Show success message
this.showSuccess();
this.form.reset();
} catch (error) {
console.error('Form submission error:', error);
} finally {
submitButton.innerHTML = originalText;
}
}
showSuccess() {
const successDiv = document.createElement('div');
successDiv.className = 'success-message show';
successDiv.innerHTML = '🎉 Message sent successfully! We\'ll get back to you soon.';
this.form.appendChild(successDiv);
setTimeout(() => {
successDiv.classList.remove('show');
setTimeout(() => successDiv.remove(), 300);
}, 5000);
}
}
// Portfolio Data Loader
class PortfolioLoader {
constructor() {
this.grid = document.getElementById('portfolio-grid');
this.init();
}
init() {
// Using static.photos for consistent placeholder images
const portfolioItems = [
{
title: "E-Commerce Revolution",
category: "Web Development",
image: "http://static.photos/technology/640x360/42",
description: "Built a scalable e-commerce platform with 300% conversion increase"
},
{
title: "Brand Identity Suite",
category: "Design",
image: "http://static.photos/workspace/640x360/133",
description: "Complete brand redesign for a Fortune 500 company"
},
{
title: "Mobile Banking App",
category: "Mobile Development",
image: "http://static.photos/abstract/640x360/99",
description: "Secure, intuitive banking app with biometric authentication"
},
{
title: "AI Dashboard",
category: "Data Visualization",
image: "http://static.photos/industry/640x360/77",
description: "Real-time analytics dashboard powered by machine learning"
},
{
title: "Social Campaign",
category: "Marketing",
image: "http://static.photos/people/640x360/21",
description: "Viral marketing campaign reaching 10M+ impressions"
},
{
title: "Secure Cloud Migration",
category: "Cybersecurity",
image: "http://static.photos/network/640x360/55",
description: "Zero-downtime migration with enhanced security protocols"
}
];
this.renderPortfolio(portfolioItems);
}
renderPortfolio(items) {
items.forEach((item, index) => {
const portfolioElement = document.createElement('portfolio-item');
portfolioElement.setAttribute('title', item.title);
portfolioElement.setAttribute('category', item.category);
portfolioElement.setAttribute('image', item.image);
portfolioElement.setAttribute('description', item.description);
// Stagger animation
setTimeout(() => {
this.grid.appendChild(portfolioElement);
}, index * 100);
});
}
}
// Testimonials Loader
class TestimonialsLoader {
constructor() {
this.container = document.getElementById('testimonials-slider');
this.currentIndex = 0;
this.testimonials = [];
this.init();
}
async init() {
try {
// Fetch real testimonials from JSONPlaceholder
const response = await fetch('https://jsonplaceholder.typicode.com/comments?_limit=5');
const data = await response.json();
this.testimonials = data.slice(0, 5).map(comment => ({
name: comment.name.split(' ').map(word =>
word.charAt(0).toUpperCase() + word.slice(1)
).join(' '),
text: comment.body.charAt(0).toUpperCase() + comment.body.slice(1),
role: ['CEO', 'Founder', 'CTO', 'Director', 'Product Manager'][Math.floor(Math.random() * 5)],
company: ['TechCorp', 'StartupX', 'Digital Dreams', 'FutureLabs', 'Innovate Inc'][Math.floor(Math.random() * 5)]
}));
this.renderTestimonials();
this.startAutoSlide();
} catch (error) {
console.error('Failed to load testimonials:', error);
this.renderFallbackTestimonials();
}
}
renderTestimonials() {
const testimonialHTML = this.testimonials.map((t, index) => `
<div class="testimonial-slide ${index === 0 ? 'active' : ''} bg-gray-800 p-8 rounded-2xl shadow-xl">
<div class="flex items-center mb-6">
<div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-secondary-500 rounded-full flex items-center justify-center text-white font-bold text-xl mr-4">
${t.name.split(' ').map(n => n[0]).join('')}
</div>
<div>
<h4 class="font-bold text-lg">${t.name}</h4>
<p class="text-primary-400 text-sm">${t.role} at ${t.company}</p>
</div>
</div>
<blockquote class="text-gray-300 text-lg italic">
<i data-feather="quote" class="w-8 h-8 text-primary-500 mb-4"></i>
"${t.text}"
</blockquote>
<div class="flex mt-6">
${Array(5).fill().map(() => '<i data-feather="star" class="w-5 h-5 text-yellow-400 fill-current"></i>').join('')}
</div>
</div>
`).join('');
this.container.innerHTML = `
<div class="relative">
${testimonialHTML}
<div class="flex justify-center mt-8 space-x-4">
${this.testimonials.map((_, index) => `
<button class="testimonial-dot w-4 h-4 rounded-full transition-all duration-300 ${index === 0 ? 'bg-primary-500' : 'bg-gray-600 hover:bg-gray-500'}" data-index="${index}"></button>
`).join('')}
</div>
</div>
`;
this.attachDotListeners();
feather.replace();
}
renderFallbackTestimonials() {
const fallback = [
{
name: "Sarah Johnson",
role: "CEO",
company: "TechVenture",
text: "NeonNexus transformed our digital presence completely. The results exceeded all expectations!"
}
];
this.testimonials = fallback;
this.renderTestimonials();
}
attachDotListeners() {
const dots = this.container.querySelectorAll('.testimonial-dot');
dots.forEach(dot => {
dot.addEventListener('click', (e) => {
this.showTestimonial(parseInt(e.target.dataset.index));
});
});
}
showTestimonial(index) {
const slides = this.container.querySelectorAll('.testimonial-slide');
const dots = this.container.querySelectorAll('.testimonial-dot');
slides.forEach(slide => slide.classList.remove('active'));
dots.forEach(dot => {
dot.classList.remove('bg-primary-500');
dot.classList.add('bg-gray-600');
});
slides[index].classList.add('active');
dots[index].classList.remove('bg-gray-600');
dots[index].classList.add('bg-primary-500');
this.currentIndex = index;
}
startAutoSlide() {
setInterval(() => {
this.currentIndex = (this.currentIndex + 1) % this.testimonials.length;
this.showTestimonial(this.currentIndex);
}, 5000);
}
}
// Mobile Menu Handler
class MobileMenuHandler {
constructor() {
this.isOpen = false;
this.init();
}
init() {
// This will be called from the navbar component
window.addEventListener('mobile-menu-toggle', (e) => {
this.isOpen = e.detail.isOpen;
document.body.style.overflow = this.isOpen ? 'hidden' : '';
});
}
}
// Custom Cursor
class CustomCursor {
constructor() {
this.cursor = document.createElement('div');
this.cursor.className = 'custom-cursor';
this.init();
}
init() {
document.body.appendChild(this.cursor);
document.addEventListener('mousemove', (e) => {
this.cursor.style.left = e.clientX + 'px';
this.cursor.style.top = e.clientY + 'px';
});
document.addEventListener('mousedown', () => {
this.cursor.style.transform = 'scale(0.8)';
});
document.addEventListener('mouseup', () => {
this.cursor.style.transform = 'scale(1)';
});
// Hide on touch devices
if ('ontouchstart' in window) {
this.cursor.style.display = 'none';
}
}
}
// Initialize everything when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
// Core managers
new ThemeManager();
new LoadingManager();
new SmoothScroll();
new ScrollAnimations();
new ContactForm();
new MobileMenuHandler();
// Data loaders
new PortfolioLoader();
new TestimonialsLoader();
// Optional features
new CustomCursor();
// Add some interactive elements
initializeInteractiveEffects();
});
function initializeInteractiveEffects() {
// Add parallax effect to hero elements
window.addEventListener('scroll', () => {
const scrolled = window.pageYOffset;
const parallaxElements = document.querySelectorAll('.animate-float');
parallaxElements.forEach((element, index) => {
const speed = 0.5 + (index * 0.1);
element.style.transform = `translateY(${scrolled * speed}px) rotate(${scrolled * 0.05}deg)`;
});
});
// Add click ripple effect to buttons
document.querySelectorAll('button, .btn-primary').forEach