|
1 | | -console.log('✓ Script.js загружен!'); |
2 | | - |
3 | | -// === НАСТРОЙКИ === |
4 | | -const WORKER_URL = 'https://polished-cake-e6c7.lakazov77.workers.dev/'; // ЗАМЕНИТЕ на ваш реальный URL! |
| 1 | +// ===== КОНФИГУРАЦИЯ ===== |
| 2 | +const WORKER_URL = 'https://muddy-resonance-4c32.lakazov77.workers.dev'; // ЗАМЕНИТЕ на ваш реальный URL Worker! |
5 | 3 |
|
| 4 | +console.log('✓ Script.js загружен!'); |
6 | 5 | console.log('Worker URL:', WORKER_URL); |
7 | 6 |
|
8 | | -// === SMOOTH SCROLL === |
9 | | -document.addEventListener('DOMContentLoaded', function() { |
10 | | - console.log('✓ DOM загружен!'); |
11 | | - |
12 | | - // Smooth scroll для навигации |
13 | | - document.querySelectorAll('a[href^="#"]').forEach(anchor => { |
14 | | - anchor.addEventListener('click', function (e) { |
15 | | - e.preventDefault(); |
16 | | - const target = document.querySelector(this.getAttribute('href')); |
17 | | - if (target) { |
18 | | - target.scrollIntoView({ |
19 | | - behavior: 'smooth', |
20 | | - block: 'start' |
21 | | - }); |
22 | | - } |
23 | | - }); |
24 | | - }); |
25 | | - |
26 | | - // === COUNTER ANIMATION === |
27 | | - function animateCounter(element, target, duration = 2000) { |
28 | | - let start = 0; |
29 | | - const increment = target / (duration / 16); |
30 | | - const timer = setInterval(() => { |
31 | | - start += increment; |
32 | | - if (start >= target) { |
33 | | - element.textContent = target + (target === 100 ? '' : '+'); |
34 | | - clearInterval(timer); |
35 | | - } else { |
36 | | - element.textContent = Math.floor(start) + (target === 100 ? '' : '+'); |
37 | | - } |
38 | | - }, 16); |
39 | | - } |
40 | | - |
41 | | - // === INTERSECTION OBSERVER === |
42 | | - const observerOptions = { |
43 | | - threshold: 0.1, |
44 | | - rootMargin: '0px 0px -50px 0px' |
45 | | - }; |
46 | | - |
47 | | - const observer = new IntersectionObserver((entries) => { |
48 | | - entries.forEach(entry => { |
49 | | - if (entry.isIntersecting) { |
50 | | - entry.target.classList.add('animated'); |
51 | | - |
52 | | - if (entry.target.classList.contains('hero-content')) { |
53 | | - const statNumbers = document.querySelectorAll('.stat-number'); |
54 | | - statNumbers.forEach(stat => { |
55 | | - const target = parseInt(stat.getAttribute('data-target')); |
56 | | - animateCounter(stat, target); |
57 | | - }); |
58 | | - } |
59 | | - } |
60 | | - }); |
61 | | - }, observerOptions); |
62 | | - |
63 | | - const animatedElements = document.querySelectorAll('.animate-on-scroll'); |
64 | | - animatedElements.forEach(el => observer.observe(el)); |
65 | | - |
66 | | - const heroContent = document.querySelector('.hero-content'); |
67 | | - if (heroContent) { |
68 | | - observer.observe(heroContent); |
69 | | - } |
70 | | - |
71 | | - // === MOBILE MENU === |
72 | | - const mobileMenuToggle = document.querySelector('.mobile-menu-toggle'); |
73 | | - const nav = document.querySelector('.nav'); |
74 | | - |
75 | | - if (mobileMenuToggle) { |
76 | | - mobileMenuToggle.addEventListener('click', () => { |
77 | | - nav.classList.toggle('active'); |
78 | | - mobileMenuToggle.classList.toggle('active'); |
79 | | - }); |
80 | | - |
81 | | - document.querySelectorAll('.nav a').forEach(link => { |
82 | | - link.addEventListener('click', () => { |
83 | | - nav.classList.remove('active'); |
84 | | - mobileMenuToggle.classList.remove('active'); |
85 | | - }); |
| 7 | +// ===== SMOOTH SCROLL ===== |
| 8 | +function scrollToContact() { |
| 9 | + const contactSection = document.getElementById('contact'); |
| 10 | + if (contactSection) { |
| 11 | + contactSection.scrollIntoView({ |
| 12 | + behavior: 'smooth', |
| 13 | + block: 'start' |
86 | 14 | }); |
87 | 15 | } |
| 16 | +} |
88 | 17 |
|
89 | | - // === КАЛЬКУЛЯТОР === |
90 | | - const calculatorForm = document.getElementById('calculator-form'); |
91 | | - const calculatorResult = document.getElementById('calculator-result'); |
92 | | - |
93 | | - if (calculatorForm) { |
94 | | - console.log('✓ Калькулятор найден!'); |
95 | | - calculatorForm.addEventListener('submit', (e) => { |
96 | | - e.preventDefault(); |
97 | | - |
98 | | - const area = parseFloat(document.getElementById('area').value); |
99 | | - const serviceType = parseFloat(document.getElementById('service-type').value); |
100 | | - const waterproofing = document.querySelector('input[name="waterproofing"]').checked ? 150 : 0; |
101 | | - const insulation = document.querySelector('input[name="insulation"]').checked ? 200 : 0; |
102 | | - |
103 | | - if (area && serviceType) { |
104 | | - const totalPricePerSqm = serviceType + waterproofing + insulation; |
105 | | - const totalPrice = area * totalPricePerSqm; |
106 | | - |
107 | | - calculatorResult.innerHTML = ` |
108 | | - <div>Примерная стоимость:</div> |
109 | | - <div style="font-size: 2rem; margin-top: 0.5rem;">${totalPrice.toLocaleString('ru-RU')} ₽</div> |
110 | | - <div style="font-size: 1rem; margin-top: 0.5rem; opacity: 0.8;">${totalPricePerSqm} ₽/м² × ${area} м²</div> |
111 | | - `; |
112 | | - calculatorResult.classList.add('show'); |
113 | | - |
114 | | - setTimeout(() => { |
115 | | - calculatorResult.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); |
116 | | - }, 100); |
117 | | - } |
118 | | - }); |
119 | | - } |
120 | | - |
121 | | - // === КОНТАКТНАЯ ФОРМА === |
122 | | - const contactForm = document.getElementById('contact-form'); |
123 | | - const formSuccess = document.getElementById('form-success'); |
| 18 | +// ===== DOM READY ===== |
| 19 | +document.addEventListener('DOMContentLoaded', function() { |
| 20 | + console.log('✓ DOM загружен!'); |
124 | 21 |
|
125 | | - if (!contactForm) { |
126 | | - console.error('✗ Форма не найдена! Проверьте id="contact-form"'); |
127 | | - } else { |
128 | | - console.log('✓ Контактная форма найдена!'); |
129 | | - |
130 | | - contactForm.addEventListener('submit', async function(e) { |
131 | | - e.preventDefault(); |
132 | | - console.log('✓ Форма отправляется!'); |
133 | | - |
134 | | - const formData = new FormData(contactForm); |
135 | | - const data = { |
136 | | - name: formData.get('name'), |
137 | | - phone: formData.get('phone'), |
138 | | - message: formData.get('message') || 'Не указано' |
139 | | - }; |
140 | | - |
141 | | - console.log('Данные формы:', data); |
142 | | - |
143 | | - const submitBtn = contactForm.querySelector('button[type="submit"]'); |
144 | | - const originalText = submitBtn.textContent; |
145 | | - submitBtn.textContent = 'Отправка...'; |
146 | | - submitBtn.disabled = true; |
147 | | - |
148 | | - try { |
149 | | - console.log('Отправляю на:', WORKER_URL); |
150 | | - |
151 | | - const response = await fetch(WORKER_URL, { |
152 | | - method: 'POST', |
153 | | - headers: { |
154 | | - 'Content-Type': 'application/json', |
155 | | - }, |
156 | | - body: JSON.stringify(data) |
157 | | - }); |
158 | | - |
159 | | - console.log('Ответ получен:', response.status); |
160 | | - |
161 | | - const result = await response.json(); |
162 | | - console.log('Результат:', result); |
163 | | - |
164 | | - if (result.success) { |
165 | | - formSuccess.innerHTML = '✓ Спасибо! Ваша заявка принята. Мы свяжемся с вами в ближайшее время.'; |
166 | | - formSuccess.classList.add('show', 'success'); |
167 | | - contactForm.reset(); |
168 | | - } else { |
169 | | - throw new Error(result.message); |
170 | | - } |
171 | | - } catch (error) { |
172 | | - console.error('Ошибка:', error); |
173 | | - formSuccess.innerHTML = '✗ Ошибка отправки. Пожалуйста, позвоните нам по телефону.'; |
174 | | - formSuccess.classList.add('show'); |
175 | | - formSuccess.style.background = '#fee2e2'; |
176 | | - formSuccess.style.color = '#dc2626'; |
177 | | - formSuccess.style.borderLeft = '4px solid #dc2626'; |
178 | | - } finally { |
179 | | - submitBtn.textContent = originalText; |
180 | | - submitBtn.disabled = false; |
181 | | - |
182 | | - setTimeout(() => { |
183 | | - formSuccess.classList.remove('show'); |
184 | | - }, 5000); |
185 | | - } |
186 | | - }); |
187 | | - } |
188 | | - |
189 | | - // === TESTIMONIALS SLIDER === |
190 | | - let currentTestimonial = 0; |
191 | | - const testimonialItems = document.querySelectorAll('.testimonial-item'); |
192 | | - const prevBtn = document.querySelector('.testimonial-prev'); |
193 | | - const nextBtn = document.querySelector('.testimonial-next'); |
194 | | - |
195 | | - function showTestimonial(index) { |
196 | | - testimonialItems.forEach((item, i) => { |
197 | | - item.classList.remove('active'); |
198 | | - if (i === index) { |
199 | | - item.classList.add('active'); |
200 | | - } |
201 | | - }); |
202 | | - } |
203 | | - |
204 | | - if (prevBtn && nextBtn && testimonialItems.length > 0) { |
205 | | - prevBtn.addEventListener('click', () => { |
206 | | - currentTestimonial = (currentTestimonial - 1 + testimonialItems.length) % testimonialItems.length; |
207 | | - showTestimonial(currentTestimonial); |
208 | | - }); |
209 | | - |
210 | | - nextBtn.addEventListener('click', () => { |
211 | | - currentTestimonial = (currentTestimonial + 1) % testimonialItems.length; |
212 | | - showTestimonial(currentTestimonial); |
213 | | - }); |
214 | | - |
215 | | - setInterval(() => { |
216 | | - currentTestimonial = (currentTestimonial + 1) % testimonialItems.length; |
217 | | - showTestimonial(currentTestimonial); |
218 | | - }, 5000); |
219 | | - } |
220 | | - |
221 | | - // === PHONE FORMATTING === |
| 22 | + // ===== PHONE FORMATTING ===== |
222 | 23 | const phoneInputs = document.querySelectorAll('input[type="tel"]'); |
223 | 24 | phoneInputs.forEach(input => { |
224 | 25 | input.addEventListener('input', function(e) { |
@@ -248,28 +49,89 @@ document.addEventListener('DOMContentLoaded', function() { |
248 | 49 | }); |
249 | 50 | }); |
250 | 51 |
|
251 | | - // === HEADER SCROLL EFFECT === |
| 52 | + // ===== CONTACT FORM ===== |
| 53 | + const contactForm = document.getElementById('contact-form'); |
| 54 | + const formSuccess = document.getElementById('form-success'); |
| 55 | + |
| 56 | + if (!contactForm) { |
| 57 | + console.error('✗ Форма не найдена! Проверьте id="contact-form"'); |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + console.log('✓ Контактная форма найдена!'); |
| 62 | + |
| 63 | + contactForm.addEventListener('submit', async function(e) { |
| 64 | + e.preventDefault(); |
| 65 | + console.log('✓ Форма отправляется!'); |
| 66 | + |
| 67 | + const formData = new FormData(contactForm); |
| 68 | + const data = { |
| 69 | + name: formData.get('name'), |
| 70 | + phone: formData.get('phone'), |
| 71 | + message: formData.get('message') || 'Не указано' |
| 72 | + }; |
| 73 | + |
| 74 | + console.log('Данные формы:', data); |
| 75 | + |
| 76 | + const submitBtn = contactForm.querySelector('button[type="submit"]'); |
| 77 | + const originalText = submitBtn.textContent; |
| 78 | + submitBtn.textContent = 'Отправка...'; |
| 79 | + submitBtn.disabled = true; |
| 80 | + |
| 81 | + try { |
| 82 | + console.log('Отправляю на:', WORKER_URL); |
| 83 | + |
| 84 | + const response = await fetch(WORKER_URL, { |
| 85 | + method: 'POST', |
| 86 | + headers: { |
| 87 | + 'Content-Type': 'application/json', |
| 88 | + }, |
| 89 | + body: JSON.stringify(data) |
| 90 | + }); |
| 91 | + |
| 92 | + console.log('Ответ получен:', response.status); |
| 93 | + |
| 94 | + const result = await response.json(); |
| 95 | + console.log('Результат:', result); |
| 96 | + |
| 97 | + if (result.success) { |
| 98 | + formSuccess.innerHTML = '✓ Спасибо! Ваша заявка принята. Мы свяжемся с вами в ближайшее время.'; |
| 99 | + formSuccess.style.background = '#4CAF50'; |
| 100 | + formSuccess.classList.add('show'); |
| 101 | + contactForm.reset(); |
| 102 | + } else { |
| 103 | + throw new Error(result.message); |
| 104 | + } |
| 105 | + } catch (error) { |
| 106 | + console.error('Ошибка:', error); |
| 107 | + formSuccess.innerHTML = '✗ Ошибка отправки. Пожалуйста, позвоните нам по телефону.'; |
| 108 | + formSuccess.style.background = '#f44336'; |
| 109 | + formSuccess.classList.add('show'); |
| 110 | + } finally { |
| 111 | + submitBtn.textContent = originalText; |
| 112 | + submitBtn.disabled = false; |
| 113 | + |
| 114 | + setTimeout(() => { |
| 115 | + formSuccess.classList.remove('show'); |
| 116 | + }, 5000); |
| 117 | + } |
| 118 | + }); |
| 119 | + |
| 120 | + // ===== HEADER SCROLL EFFECT ===== |
252 | 121 | const header = document.querySelector('.header'); |
| 122 | + let lastScroll = 0; |
| 123 | + |
253 | 124 | window.addEventListener('scroll', () => { |
254 | 125 | const currentScroll = window.pageYOffset; |
255 | 126 |
|
256 | 127 | if (currentScroll > 100) { |
257 | | - header.style.boxShadow = '0 4px 20px rgba(0,0,0,0.15)'; |
| 128 | + header.style.boxShadow = '0 4px 20px rgba(0,0,0,0.1)'; |
258 | 129 | } else { |
259 | | - header.style.boxShadow = '0 2px 10px rgba(0,0,0,0.1)'; |
| 130 | + header.style.boxShadow = '0 2px 10px rgba(0,0,0,0.05)'; |
260 | 131 | } |
| 132 | + |
| 133 | + lastScroll = currentScroll; |
261 | 134 | }); |
262 | | - |
263 | | - // === PARALLAX (desktop only) === |
264 | | - if (window.innerWidth > 768) { |
265 | | - window.addEventListener('scroll', () => { |
266 | | - const scrolled = window.pageYOffset; |
267 | | - const hero = document.querySelector('.hero'); |
268 | | - if (hero && scrolled < hero.offsetHeight) { |
269 | | - hero.style.backgroundPositionY = scrolled * 0.5 + 'px'; |
270 | | - } |
271 | | - }); |
272 | | - } |
273 | 135 | }); |
274 | 136 |
|
275 | 137 | console.log('✓ Script.js полностью выполнен!'); |
0 commit comments