(function ($) { 'use strict'; $(function () { const $expertise = $('.expertise'); if (!$expertise.length || typeof Swiper !== 'function') { return; } const $slider = $expertise.find('.expertise__cases'); const $wrapper = $expertise.find('.expertise__track'); const $tabs = $expertise.find('.expertise__tab'); const sourceSlides = $wrapper.find('.expertise-card').map(function () { const $slide = $(this); return { group: $slide.data('expertise-group'), html: this.outerHTML, }; }).get(); let expertiseSwiper = null; let activeFilter = null; const getSlidesByFilter = function (filter) { return sourceSlides.filter(function (slide) { return slide.group === filter; }); }; const updateTabs = function (filter) { $tabs.each(function () { const $tab = $(this); const isActive = $tab.data('expertise-filter') === filter; $tab .toggleClass('is-active', isActive) .attr({ 'aria-selected': String(isActive), 'aria-pressed': String(isActive), }); }); }; const destroySlider = function () { if (!expertiseSwiper) { return; } expertiseSwiper.destroy(true, true); expertiseSwiper = null; }; const getLoopSlidesHtml = function (slides) { // Для loop в Swiper важно, чтобы реальных слайдов было заметно больше, // чем помещается в видимой области. Иначе Swiper отключает loop на широких экранах. const minSlidesForLoop = 24; const repeatCount = Math.max(1, Math.ceil(minSlidesForLoop / slides.length)); let html = ''; for (let i = 0; i < repeatCount; i += 1) { slides.forEach(function (slide) { html += slide.html; }); } return html; }; const initSlider = function () { const slidesCount = $wrapper.children('.swiper-slide').length; const loopEnabled = slidesCount > 1; expertiseSwiper = new Swiper($slider[0], { slidesPerView: 'auto', spaceBetween: 16, speed: 650, grabCursor: true, allowTouchMove: true, watchOverflow: false, loop: loopEnabled, loopedSlides: Math.min(12, slidesCount), loopAdditionalSlides: Math.min(12, slidesCount), loopPreventsSliding: false, normalizeSlideIndex: true, observer: true, observeParents: true, breakpoints: { 768: { spaceBetween: 24, }, 1200: { spaceBetween: 32, }, }, }); }; const renderSlides = function (filter) { const slides = getSlidesByFilter(filter); if (!slides.length) { return; } destroySlider(); $wrapper.html(getLoopSlidesHtml(slides)); initSlider(); }; const setActiveFilter = function (filter) { if (activeFilter === filter || !getSlidesByFilter(filter).length) { return; } activeFilter = filter; updateTabs(filter); renderSlides(filter); }; const initialFilter = $tabs.filter('.is-active').first().data('expertise-filter') || $tabs.first().data('expertise-filter'); setActiveFilter(initialFilter); $tabs.on('click', function () { setActiveFilter($(this).data('expertise-filter')); }); }); })(jQuery); (function ($) { 'use strict'; $(function () { const $results = $('.results'); if (!$results.length) { return; } $results.addClass('is-animation-ready'); const showResults = function (target) { $(target).addClass('is-in-view'); }; if (!('IntersectionObserver' in window)) { $results.each(function () { showResults(this); }); return; } const observer = new IntersectionObserver(function (entries, currentObserver) { entries.forEach(function (entry) { if (!entry.isIntersecting) { return; } showResults(entry.target); currentObserver.unobserve(entry.target); }); }, { threshold: 0.24, rootMargin: '0px 0px -12% 0px', }); $results.each(function () { observer.observe(this); }); }); })(jQuery); (function ($) { 'use strict'; $(function () { const $faq = $('.faq'); if (!$faq.length) { return; } $faq.on('click', '.faq-item__button', function () { const $button = $(this); const $item = $button.closest('.faq-item'); const $panel = $item.find('.faq-item__panel').first(); const isOpen = $button.attr('aria-expanded') === 'true'; $button.attr('aria-expanded', String(!isOpen)); if (isOpen) { $panel.stop(true, true).slideUp(220, function () { $panel.attr('hidden', true).removeAttr('style'); }); } else { $panel.removeAttr('hidden').hide().stop(true, true).slideDown(220, function () { $panel.removeAttr('style'); }); } }); }); })(jQuery); (function ($) { 'use strict'; $(function () { const $forms = $('.contact-sentence'); if (!$forms.length) { return; } const options = { task: ['лендинг', 'интернет-магазин', 'интеграцию', 'дизайн', 'доработку сайта'], method: ['Telegram', 'WhatsApp', 'звонок', 'email'], time: ['09:00–12:00', '12:00–15:00', '15:00–18:00', 'любое время'], }; let $dateInput = $('.contact-date-input'); if (!$dateInput.length) { $dateInput = $('').appendTo('body'); } const cleanValue = function ($field) { const text = $.trim($field.text()).replace(/\s+/g, ' '); const placeholder = $.trim($field.data('placeholder') || ''); const normalized = text.replace(/[()]/g, '').replace(/▾/g, '').trim(); if ($field.hasClass('is-placeholder') || normalized === placeholder) { return ''; } return normalized; }; const getPlaceholderText = function ($field) { const placeholder = $.trim($field.data('placeholder') || ''); const withArrow = $field.hasClass('contact-field--selector'); return '(' + placeholder + (withArrow ? ' ▾' : '') + ')'; }; const setFieldValue = function ($field, value, isPlaceholder) { const text = isPlaceholder ? getPlaceholderText($field) : value; $field .text(text) .toggleClass('is-placeholder', !!isPlaceholder) .toggleClass('is-filled', !isPlaceholder && !!value) .removeClass('is-error'); updateHidden($field.closest('form')); }; const updateHidden = function ($form) { $form.find('.contact-field').each(function () { const $field = $(this); const name = $field.data('field'); if (!name) { return; } $form.find('input[name="' + name + '"]').val(cleanValue($field)); }); }; const selectAll = function (el) { const range = document.createRange(); const selection = window.getSelection(); range.selectNodeContents(el); selection.removeAllRanges(); selection.addRange(range); }; const setCaretEnd = function (el) { const range = document.createRange(); const selection = window.getSelection(); range.selectNodeContents(el); range.collapse(false); selection.removeAllRanges(); selection.addRange(range); }; const formatPhone = function (value) { const raw = String(value || '').replace(/\s+/g, ''); const hasPlus = raw.indexOf('+') === 0; const digits = raw.replace(/\D/g, '').slice(0, 11); if (!digits) { return hasPlus ? '+' : ''; } let formatted = hasPlus || digits.charAt(0) === '7' ? '+' : ''; formatted += digits.slice(0, 1); if (digits.length > 1) { formatted += ' ' + digits.slice(1, 4); } if (digits.length > 4) { formatted += ' ' + digits.slice(4, 7); } if (digits.length > 7) { formatted += ' ' + digits.slice(7, 9); } if (digits.length > 9) { formatted += ' ' + digits.slice(9, 11); } return formatted; }; const openDropdown = function ($field) { const type = $field.data('type'); const values = options[type] || []; if (!values.length) { return; } $('.contact-dropdown').remove(); const rect = $field[0].getBoundingClientRect(); const $dropdown = $('