// Shared JavaScript across all pages // Initialize the application document.addEventListener('DOMContentLoaded', function() { initializeApp(); setupEventListeners(); loadInitialData(); }); // Global state let appState = { events: [], resources: [], currentLanguage: 'en', darkMode: true, translations: { en: { nav: { about: "About", lessons: "Lessons", events: "Events", resources: "Resources", testimonials: "Testimonials", gallery: "Gallery", contact: "Contact" }, hero: { title: "Unlock Your Musical Potential", subtitle: "Professional piano instruction tailored to your unique journey. From classical masterpieces to contemporary hits.", explore_lessons: "Explore Lessons", book_trial: "Book Trial Lesson" }, about: { title: "About Your Teacher", content1: "With over 15 years of teaching experience and a Master's degree in Piano Performance, I'm passionate about helping students of all ages discover the joy of music.", content2: "My teaching philosophy centers on creating a supportive, engaging environment where students can develop both technical skills and musical expression at their own pace.", specialties: { classical: "Classical", jazz: "Jazz", contemporary: "Contemporary", music_theory: "Music Theory" }, lessons: { title: "Lessons & Services", subtitle: "Flexible lesson formats designed to fit your schedule and learning preferences" }, contact: { title: "Get In Touch", subtitle: "Ready to start your musical journey? Book a trial lesson today!" }, form: { name: "Full Name", email: "Email Address", phone: "Phone Number", message: "Message", trial_label: "I'm interested in a trial lesson", send: "Send Message" } }, he: { nav: { about: "אודות", lessons: "שיעורים", events: "אירועים", resources: "משאבים", testimonials: "המלצות", gallery: "גלריה", contact: "צור קשר" }, hero: { title: "שחרר את הפוטנציאל המוזיקלי שלך", subtitle: "הוראת פסנתר מקצועית המותאמת למסע הייחודי שלך. מיצירות קלאסיות ועד להיטים עכשוויים.", explore_lessons: "חקור שיעורים", book_trial: "הזמן שיעור ניסיון" }, about: { title: "אודות המורה שלך", content1: "עם מעל 15 שנות ניסיון בהוראה ותואר שני בביצוע פסנתר, אני נלהב לעזור לתלמידים בכל הגילאים לגלות את השמחה במוזיקה.", content2: "פילוסופיית ההוראה שלי מתמקדת ביצירת סביבה תומכת ומעוררת עניין בה תלמידים יכולים לפתח מיומנויות טכניות והבעה מוזיקלית בקצב שלהם.", specialties: { classical: "קלאסי", jazz: "ג'אז", contemporary: "עכשווי", music_theory: "תורת המוזיקה" }, lessons: { title: "שיעורים ושירותים", subtitle: "פורמטים גמישים של שיעורים שנועדו להתאים ללו\"ז שלך ולהעדפות הלמידה" }, contact: { title: "צור קשר", subtitle: "מוכן להתחיל את המסע המוזיקלי שלך? הזמן שיעור ניסיון היום!" }, form: { name: "שם מלא", email: "כתובת אימייל", phone: "מספר טלפון", message: "הודעה", trial_label: "אני מעוניין/ת בשיעור ניסיון", send: "שלח הודעה" } }, ru: { nav: { about: "О нас", lessons: "Уроки", events: "События", resources: "Ресурсы", testimonials: "Отзывы", gallery: "Галерея", contact: "Контакты" }, hero: { title: "Раскройте свой музыкальный потенциал", subtitle: "Профессиональное обучение игре на фортепиано, адаптированное к вашему уникальному пути. От классических шедевров до современных хитов.", explore_lessons: "Изучить уроки", book_trial: "Записаться на пробный урок" }, about: { title: "О вашем преподавателе", content1: "С более чем 15-летним опытом преподавания и степенью магистра в области фортепианного исполнения, я увлечен тем, что помогаю ученикам всех возрастов открыть для себя радость музыки.", content2: "Моя философия преподавания сосредоточена на создании поддерживающей, увлекательной среды, где ученики могут развивать как технические навыки, так и музыкальную выразительность в своем собственном темпе.", specialties: { classical: "Классика", jazz: "Джаз", contemporary: "Современный", music_theory: "Теория музыки" }, lessons: { title: "Уроки и услуги", subtitle: "Гибкие форматы уроков, разработанные с учетом вашего расписания и предпочтений в обучении" }, contact: { title: "Свяжитесь с нами", subtitle: "Готовы начать свой музыкальный путь? Запишитесь на пробный урок сегодня!" }, form: { name: "Полное имя", email: "Адрес электронной почты", phone: "Номер телефона", message: "Сообщение", trial_label: "Я заинтересован(а) в пробном уроке", send: "Отправить сообщение" } } } }; // Initialize application function initializeApp() { console.log('Melodic Keys Academy initialized'); // Initialize language initializeLanguage(); // Set initial dark mode document.documentElement.classList.add('dark'); // Load initial data loadEvents(); loadResources(); // Setup analytics (placeholder) setupAnalytics(); // Setup privacy consent setupPrivacyConsent(); } // Setup event listeners function setupEventListeners() { // Contact form submission const contactForm = document.getElementById('contact-form'); if (contactForm) { contactForm.addEventListener('submit', handleContactFormSubmit); } // Language switcher const langSwitchers = document.querySelectorAll('.lang-switch'); langSwitchers.forEach(switcher => { switcher.addEventListener('click', handleLanguageSwitch); }); } // Load initial data function loadInitialData() { // These would typically come from an API loadEvents(); loadResources(); } // Events management async function loadEvents() { try { // Simulate API call const mockEvents = [ { id: 1, title: 'Spring Recital', date: '2024-03-15', time: '2:00 PM', type: 'recital', location: 'Community Center', description: 'Annual spring student recital showcasing progress' }, { id: 2, title: 'Music Theory Workshop', date: '2024-03-22', time: '4:00 PM', type: 'workshop', location: 'Studio', description: 'Interactive workshop on music fundamentals' }, { id: 3, title: 'Summer Registration Opens', date: '2024-04-01', time: 'All Day', type: 'registration', location: 'Online', description: 'Registration for summer lessons and camps' } ]; appState.events = mockEvents; renderEvents(); } catch (error) { console.error('Error loading events:', error); } } function renderEvents() { const container = document.getElementById('events-container'); if (!container) return; container.innerHTML = appState.events.map(event => `
${event.type}

${event.title}

${formatDate(event.date)} at ${event.time}
${event.location}

${event.description}

`).join(''); feather.replace(); } function loadMoreEvents() { // In a real app, this would load more events from an API console.log('Loading more events...'); // Show loading state const container = document.getElementById('events-container'); if (container) { container.innerHTML += `
`; // Simulate API delay setTimeout(() => { const additionalEvents = [ { id: 4, title: 'Jazz Improvisation Class', date: '2024-04-05', time: '5:00 PM', type: 'class', location: 'Studio', description: 'Learn the art of jazz improvisation' } ]; appState.events = [...appState.events, ...additionalEvents]; renderEvents(); }, 1000); } // Resources management async function loadResources() { try { // Simulate API call const mockResources = [ { id: 1, title: 'Beginner Practice Routine', type: 'video', category: 'practice', description: 'Daily exercises for new piano students' }, { id: 2, title: 'Classical Repertoire Collection', type: 'sheet_music', category: 'repertoire', description: 'Essential pieces for developing technique' } ]; appState.resources = mockResources; renderResources(); } catch (error) { console.error('Error loading resources:', error); } } function renderResources() { const container = document.getElementById('resources-content'); if (!container) return; container.innerHTML = `

Featured Resources

${appState.resources.map(resource => `

${resource.title}

${resource.description}

`).join('')}
`; feather.replace(); } function getResourceIcon(type) { const icons = { video: 'play-circle', sheet_music: 'music', article: 'file-text', audio: 'headphones' }; return icons[type] || 'file'; } // Contact form handling async function handleContactFormSubmit(event) { event.preventDefault(); const formData = new FormData(event.target); const data = Object.fromEntries(formData); try { // Show loading state const submitBtn = event.target.querySelector('button[type="submit"]'); const originalText = submitBtn.textContent; submitBtn.textContent = 'Sending...'; submitBtn.disabled = true; // Simulate API call await new Promise(resolve => setTimeout(resolve, 1500)); // Show success message showNotification('Message sent successfully! We\'ll get back to you soon.', 'success'); // Reset form event.target.reset(); submitBtn.textContent = originalText; submitBtn.disabled = false; } catch (error) { console.error('Error sending message:', error); showNotification('Error sending message. Please try again.', 'error'); } } // Language initialization and switching function initializeLanguage() { const savedLang = localStorage.getItem('preferredLanguage'); const browserLang = navigator.language.split('-')[0]; let defaultLang = 'en'; if (savedLang) { defaultLang = savedLang; } else if (['he', 'ru'].includes(browserLang)) { defaultLang = browserLang; } switchLanguage(defaultLang); } function switchLanguage(lang) { appState.currentLanguage = lang; localStorage.setItem('preferredLanguage', lang); // Update HTML attributes document.documentElement.setAttribute('lang', lang); if (lang === 'he') { document.documentElement.setAttribute('dir', 'rtl'); } else { document.documentElement.setAttribute('dir', 'ltr'); } updatePageContent(); } function updatePageContent() { const currentLang = appState.currentLanguage; const t = appState.translations?.[currentLang]; if (!t) return; // Update meta tags document.title = 'Melodic Keys Academy'; // Update navigation updateNavigationText(); // Update hero section updateHeroSection(); // Update about section updateAboutSection(); // Update contact section updateContactSection(); } function updateNavigationText() { const currentLang = appState.currentLanguage; const t = appState.translations?.[currentLang]?.nav; if (!t) return; // Update navbar links const navLinks = document.querySelectorAll('a[href="#about"], a[href="#lessons"], a[href="#events"], a[href="#resources"], a[href="#testimonials"], a[href="#gallery"], a[href="#contact"]'); navLinks.forEach(link => { const href = link.getAttribute('href'); if (href === '#about') link.textContent = t.about; else if (href === '#lessons') link.textContent = t.lessons; else if (href === '#events') link.textContent = t.events; else if (href === '#resources') link.textContent = t.resources; else if (href === '#testimonials') link.textContent = t.testimonials; else if (href === '#gallery') link.textContent = t.gallery; else if (href === '#contact') link.textContent = t.contact; }); } function updateHeroSection() { const currentLang = appState.currentLanguage; const t = appState.translations?.[currentLang]?.hero; if (!t) return; const heroTitle = document.querySelector('section h1'); const heroSubtitle = document.querySelector('section p.text-xl'); const heroButtons = document.querySelectorAll('section a'); if (heroTitle && t.title) heroTitle.textContent = t.title; if (heroSubtitle && t.subtitle) heroSubtitle.textContent = t.subtitle; if (heroButtons[0] && t.explore_lessons) heroButtons[0].textContent = t.explore_lessons; if (heroButtons[1] && t.book_trial) heroButtons[1].textContent = t.book_trial; } function updateAboutSection() { const currentLang = appState.currentLanguage; const t = appState.translations?.[currentLang]?.about; if (!t) return; const aboutTitle = document.querySelector('#about h2'); const aboutContent = document.querySelectorAll('#about p.text-lg'); if (aboutTitle && t.title) aboutTitle.textContent = t.title; if (aboutContent[0] && t.content1) aboutContent[0].textContent = t.content1; if (aboutContent[1] && t.content2) aboutContent[1].textContent = t.content2; // Update specialties const specialties = document.querySelectorAll('#about span'); if (specialties[0] && t.specialties?.classical) specialties[0].textContent = t.specialties.classical; if (specialties[1] && t.specialties?.jazz) specialties[1].textContent = t.specialties.jazz; if (specialties[2] && t.specialties?.contemporary) specialties[2].textContent = t.specialties.contemporary; if (specialties[3] && t.specialties?.music_theory) specialties[3].textContent = t.specialties.music_theory; } function updateContactSection() { const currentLang = appState.currentLanguage; const t = appState.translations?.[currentLang]?.contact; if (!t) return; const contactTitle = document.querySelector('#contact h2'); const contactSubtitle = document.querySelector('#contact p.text-xl'); const contactForm = document.querySelector('#contact-form'); if (contactTitle && t.title) contactTitle.textContent = t.title; if (contactSubtitle && t.subtitle) contactSubtitle.textContent = t.subtitle; // Update form labels const formLabels = contactForm?.querySelectorAll('label'); const formButton = contactForm?.querySelector('button'); if (contactTitle && t.title) contactTitle.textContent = t.title; if (contactSubtitle && t.subtitle) contactSubtitle.textContent = t.subtitle; if (formLabels[0] && t.form?.name) formLabels[0].textContent = t.form.name; if (formLabels[1] && t.form?.email) formLabels[1].textContent = t.form.email; if (formLabels[2] && t.form?.phone) formLabels[2].textContent = t.form.phone; if (formLabels[3] && t.form?.message) formLabels[3].textContent = t.form.message; if (formLabels[4] && t.form?.trial_label) formLabels[4].textContent = t.form.trial_label; if (formButton && t.form?.send) formButton.textContent = t.form.send; } function updateURL(lang) { const currentPath = window.location.pathname; const newPath = `/${lang}${currentPath.replace(/^\/(en|he|ru)/, '')}`; // Only update URL if it's different from current if (!currentPath.startsWith(`/${lang}`)) { window.history.replaceState({}, '', newPath); } } function updateStructuredData() { const script = document.querySelector('script[type="application/ld+json"]'); if (script) { const data = JSON.parse(script.textContent); data.availableLanguage = ['English', 'Hebrew', 'Russian']; script.textContent = JSON.stringify(data); } } // Handle language change events document.addEventListener('languageChange', (e) => { switchLanguage(e.detail.lang); }); // Notification system function showNotification(message, type = 'info') { // Create notification element const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg transform transition-all duration-300 ${ type === 'success' ? 'bg-green-500 text-white' : type === 'error' ? 'bg-red-500 text-white' : 'bg-primary-500 text-white' }`; notification.textContent = message; document.body.appendChild(notification); // Animate in setTimeout(() => { notification.classList.add('translate-x-0', 'opacity-100'); notification.classList.remove('translate-x-full', 'opacity-0'); }, 100); // Auto remove after 5 seconds setTimeout(() => { notification.classList.remove('translate-x-0', 'opacity-100'); notification.classList.add('translate-x-full', 'opacity-0'); setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 300); }, 5000); } // Analytics setup (placeholder) function setupAnalytics() { // In a real app, this would initialize Google Analytics, etc. console.log('Analytics initialized'); } // Privacy consent banner function setupPrivacyConsent() { // Check if consent already given const consentGiven = localStorage.getItem('privacyConsent'); if (!consentGiven) { // Create consent banner const banner = document.createElement('div'); banner.className = 'fixed bottom-0 left-0 right-0 bg-gray-800 border-t border-gray-700 p-4 z-40">

We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.'; banner.innerHTML = `

We use cookies to improve your experience. Learn more

`; document.body.appendChild(banner); } } function acceptPrivacyConsent() { localStorage.setItem('privacyConsent', 'true'); document.querySelector('.privacy-banner').remove(); } function declinePrivacyConsent() { localStorage.setItem('privacyConsent', 'false'); document.querySelector('.privacy-banner').remove(); } // Utility functions function formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); } // Performance monitoring if ('performance' in window) { window.addEventListener('load', () => { const perfData = performance.timing; const loadTime = perfData.loadEventEnd - perfData.navigationStart; console.log(`Page loaded in ${loadTime}ms`); }); // Service Worker registration (for PWA capabilities) if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => console.log('SW registered: ', registration)) .catch(registrationError => console.log('SW registration failed: ', registrationError)); }); } // Export for module usage if needed if (typeof module !== 'undefined' && module.exports) { module.exports = { initializeApp, loadEvents, loadResources }; }