Заметки
Вэфир

Инструкция по установке Вэфир

1) Добавляем блок галереи GL01
Скругление блока на ваш вкус. Высоту не указываем!
2) Добавляем зероблок.
В него переносим макеты из фигмы или создаём свои используя автолейауты.
Настраиваем позиционирование зеро блока. Выбираем absolute и visible.
3) Добавляем блок T123.
В него добавляем первый код. В коде меняем айдишник rec876494170 на свой.
<style>
/* Контейнер для каждого буллета (превью + прогресс-бар) */
#rec876494170 .t-slds__bullet {
    position: relative;
    overflow: visible;  /* чтобы превью не обрезались */
    width: 186px;        /* настройте размеры по необходимости */
    height: 120px;
    display: inline-block;
    margin: 0 0px;
}

/* Скрываем стандартные кнопки */
#rec876494170 .t-slds__bullet button {
    display: none;
}

/* Стили для превью-изображения */
#rec876494170 .t-slds__bullet img.bullet-preview {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border: 0px solid #fff;
    border-radius: 16px;
    background-color: #fff;
}

/* Прогресс-бар – псевдоэлемент, расположенный внизу превью */
#rec876494170 .t-slds__bullet::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    width: 0%;
    height: 8px;              /* высота полоски */
    border-radius: 6px;
    background-color: #AAF931; /* цвет прогресс-бара */
}

/* Запуск анимации прогресс-бара для активного буллета */
#rec876494170 .t-slds__bullet.active-progress::after {
    animation: progressBar var(--slide-duration) linear forwards;
}

@keyframes progressBar {
    from { width: 0%; }
    to { width: 100%; }
}

/* Базовый стиль для изображения слайдов - всегда увеличено на 10% */
#rec876494170 .t-slds__bgimg {
    transform: scale(1.1);
}

/* Эффекты для изображений слайдов */
/* Плавное увеличение (zoom in) */
@keyframes effectZoomIn {
    from { transform: scale(1.1); }
    to { transform: scale(1.3); }
}
.effect-zoom-in {
    animation: effectZoomIn var(--slide-duration) ease-in-out forwards;
}

/* Плавное уменьшение (zoom out) */
@keyframes effectZoomOut {
    from { transform: scale(1.3); }
    to { transform: scale(1.1); }
}
.effect-zoom-out {
    animation: effectZoomOut var(--slide-duration) ease-in-out forwards;
}

/* Смещение влево */
@keyframes effectShiftLeft {
    from { transform: scale(1.1) translateX(0); }
    to { transform: scale(1.1) translateX(-20px); }
}
.effect-shift-left {
    animation: effectShiftLeft var(--slide-duration) ease-in-out forwards;
}

/* Смещение вправо */
@keyframes effectShiftRight {
    from { transform: scale(1.1) translateX(0); }
    to { transform: scale(1.1) translateX(20px); }
}
.effect-shift-right {
    animation: effectShiftRight var(--slide-duration) ease-in-out forwards;
}

/* Смещение вверх */
@keyframes effectShiftUp {
    from { transform: scale(1.1) translateY(0); }
    to { transform: scale(1.1) translateY(-20px); }
}
.effect-shift-up {
    animation: effectShiftUp var(--slide-duration) ease-in-out forwards;
}

/* Смещение вниз */
@keyframes effectShiftDown {
    from { transform: scale(1.1) translateY(0); }
    to { transform: scale(1.1) translateY(20px); }
}
.effect-shift-down {
    animation: effectShiftDown var(--slide-duration) ease-in-out forwards;
}

/* Панорамирование (эффект Кена Бернса) */
@keyframes effectPan {
    from { transform: scale(1.1) translate(0, 0); }
    to { transform: scale(1.1) translate(-10px, -10px); }
}
.effect-pan {
    animation: effectPan var(--slide-duration) ease-in-out forwards;
}

.t-width_12 {
    border-radius: 30px;
}

@media screen and (max-width: 640px) {
/* Контейнер для каждого буллета (превью + прогресс-бар) */
#rec876494170 .t-slds__bullet {
    width: 30px;        /* настройте размеры по необходимости */
    height: 30px;
    display: inline-block;
    margin: 0 0px;
    }
    
/* Стили для превью-изображения */
#rec876494170 .t-slds__bullet img.bullet-preview {
    border-radius: 8px;
  }

/* Прогресс-бар – псевдоэлемент, расположенный внизу превью */
#rec876494170 .t-slds__bullet::after {
    height: 2px;              /* высота полоски */
    border-radius: 2px;
    background-color: #AAF931; /* цвет прогресс-бара */
}
.t-width_12 {
    border-radius: 0px;
    height: 500px;

}

.t670__imgwrapper {
    position: relative;
    height: 500px;
}

}
</style>

<script>
document.addEventListener('DOMContentLoaded', function () {
    const TCDid = '#rec876494170'; /* Id блока */
    const recBlock = document.querySelector(TCDid);
    if (!recBlock) {
        console.error("Блок " + TCDid + " не найден");
        return;
    }
    
    // Отключение функции остановки слайдера при наведении (если нужно)
    const sliderWrapper = recBlock.querySelector('.t-slds__items-wrapper');
    if (sliderWrapper) {
        sliderWrapper.addEventListener('mouseover', function () {
            sliderWrapper.setAttribute('data-slider-stopped', '');
        });
        const observerStop = new MutationObserver(function (mutations) {
            mutations.forEach(function (mutation) {
                if (mutation.attributeName === 'data-slider-stopped' &&
                    sliderWrapper.getAttribute('data-slider-stopped') === 'yes') {
                    sliderWrapper.setAttribute('data-slider-stopped', '');
                }
            });
        });
        observerStop.observe(sliderWrapper, {
            attributes: true,
            attributeFilter: ['data-slider-stopped'],
        });
    }
    
    // Получаем все буллеты (превью) и слайдер
    const bullets = recBlock.querySelectorAll(".t-slds__bullet");
    const slider = recBlock.querySelector(".t-slds__items-wrapper");
    if (!bullets.length || !slider) {
        console.error("Не найдены буллеты или слайдер");
        return;
    }
    
    // Время смены слайда (в мс)
    let slideTimeout = parseInt(slider.getAttribute("data-slider-timeout"), 10) || 3000;
    recBlock.style.setProperty("--slide-duration", slideTimeout + "ms");
    
    // Для каждого буллета добавляем превью из соответствующего слайда
    bullets.forEach(bullet => {
        let bulletNum = parseInt(bullet.getAttribute("data-slide-bullet-for"), 10);
        // Предполагаем, что слайды нумеруются так же, как буллеты (например, 1-4)
        let slideIndex = bulletNum;
        let slide = recBlock.querySelector(`.t-slds__item[data-slide-index="${slideIndex}"]`);
        if (!slide) {
            console.warn(`Слайд с data-slide-index="${slideIndex}" не найден`);
            return;
        }
        
        let imgWrapper = slide.querySelector(".t670__imgwrapper");
        if (!imgWrapper) {
            console.warn(`imgWrapper не найден в слайде ${slideIndex}`);
            return;
        }
        
        let imageUrl = null;
        let bgImg = imgWrapper.querySelector(".t-slds__bgimg");
        if (bgImg) {
            imageUrl = bgImg.getAttribute("data-original");
        }
        // Фолбэк: если data-original пустой, берем URL из meta-тега
        if (!imageUrl) {
            let meta = slide.querySelector('meta[itemprop="image"]');
            if (meta) {
                imageUrl = meta.getAttribute("content");
            }
        }
        if (!imageUrl) {
            console.warn(`URL изображения не найден в слайде ${slideIndex}`);
            return;
        }
        
        // Создаём элемент превью
        let previewImg = document.createElement("img");
        previewImg.src = imageUrl;
        previewImg.alt = "Превью";
        previewImg.className = "bullet-preview";
        bullet.appendChild(previewImg);
    });
    
    // Используем MutationObserver для отслеживания изменения активного слайда
    let currentActiveSlide = null;
    const slides = recBlock.querySelectorAll(".t-slds__item");
    slides.forEach(slide => {
        const observerSlide = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                if (mutation.attributeName === "class" && slide.classList.contains("t-slds__item_active")) {
                    if (slide !== currentActiveSlide) {
                        currentActiveSlide = slide;
                        updateSlideEffect(slide);
                    }
                }
            });
        });
        observerSlide.observe(slide, { attributes: true });
    });
    
    // Функция для применения случайного эффекта к активному слайду
    function updateSlideEffect(activeSlide) {
        // Находим элемент с изображением внутри активного слайда
        const bgImg = activeSlide.querySelector(".t-slds__bgimg");
        if (!bgImg) return;
        
        // Список эффектов
        const effects = [
            "effect-zoom-in",
            "effect-zoom-out",
            "effect-shift-left",
            "effect-shift-right",
            "effect-shift-up",
            "effect-shift-down",
            "effect-pan"
        ];
        
        // Выбираем случайный эффект
        const randomIndex = Math.floor(Math.random() * effects.length);
        const chosenEffect = effects[randomIndex];
        
        // Убираем предыдущие эффекты
        bgImg.classList.remove(...effects);
        // Принудительный reflow для сброса анимации
        void bgImg.offsetWidth;
        // Применяем выбранный эффект
        bgImg.classList.add(chosenEffect);
        console.log("Применен эффект", chosenEffect, "для слайда", activeSlide.getAttribute("data-slide-index"));
    }
    
    // Функция обновления прогресс-бара по активному буллету
    function updateProgress() {
        // Сбрасываем все активные прогресс-бары
        bullets.forEach(bullet => bullet.classList.remove("active-progress"));
        // Находим буллет с классом, установленным слайдером (t-slds__bullet_active)
        let activeBullet = recBlock.querySelector(".t-slds__bullet_active");
        if (activeBullet) {
            activeBullet.classList.add("active-progress");
            console.log("Запущен прогресс-бар для буллета", activeBullet.getAttribute("data-slide-bullet-for"));
        } else {
            console.log("Активный буллет не найден");
        }
    }
    
    // Инициализация прогресс-бара
    updateProgress();
    // Обновляем прогресс-бары через заданный интервал смены слайда
    let progressInterval = setInterval(updateProgress, slideTimeout);
    // Обновляем после завершения анимации слайда
    slider.addEventListener("transitionend", updateProgress);
    
    // Обработчик клика по превью
    bullets.forEach(bullet => {
        bullet.addEventListener("click", function(e) {
            // Если клик по уже активному буллету – ничего не делаем
            if (bullet.classList.contains("active-progress")) return;
    
            console.log("Клик по буллету", bullet.getAttribute("data-slide-bullet-for"));
            // Сброс анимации у всех превью
            bullets.forEach(b => {
                b.classList.remove("active-progress");
                void b.offsetWidth;
            });
            
            // Останавливаем автопереход
            clearInterval(progressInterval);
            
            // Ждем 800 мс для надежной синхронизации
            setTimeout(() => {
                updateProgress(); // Обновляем активный буллет и прогресс-бар
                // Перезапускаем автопереход
                progressInterval = setInterval(updateProgress, slideTimeout);
            }, 800);
        });
    });
});
</script>
Ваш айдишник можно увидеть в настройках блока GL01.
3) Во втором коде, находящимся ниже описаны стили только для голосовалки, как в примере на странице https://piktografika.ru/vefir-uluchshennyy-slayder-dlya-saytov-na-tilde. Если нужно вместо нее добавить другой блок, то нужно менять этот код, т.е. для другого блока нужны будут другие стили естественно.

Если оставлять этот, то нужно повторить предыдущие шаги. Также добавляем блок T123, добавляем в него код, меняем айдишники. Тут нужно заменитьь два айдишника. Первый это код сладера, второй блок голосовалки. Важно расположить этот блок в самом низу вашей страницы.
<style>
    #rec876545440 .t797__wrapper {
    border-radius: 16px;
    background: rgba(198, 198, 198, 0.6);
    backdrop-filter: blur(12px);
    padding: 20px 10px 25px;
}

.t797__wrapper_padding {
    padding: 0;
    background: rgba(61, 61, 61, 0.39);
    backdrop-filter: blur(12px);
}

.t794__title {
    margin-bottom: 10px;
}

/* Стили для контейнера */
#rec876494170 .t-slds__container.target-container {
    position: relative !important;
}

/* Стили для перемещаемого блока */
.moving-block {
    position: absolute !important;
    bottom: 0 !important;
    right: 20px !important;
    z-index: 10 !important;
    padding: 20px !important;
    box-sizing: border-box !important;
    width: auto !important;
    height: auto !important;
}

@media screen and (max-width: 640px) {
    
    #rec876545440 .t797__wrapper {
    border-radius: 10px;
    padding: 10px 0px 5px;
}
    
    /* Стили для перемещаемого блока */
.moving-block {
    position: absolute !important;
    bottom: 20px !important;
    right: 0px !important;
    z-index: 10 !important;
    padding: 0px !important;
}

}
</style>

<script>
document.addEventListener("DOMContentLoaded", function() {
    // Находим элементы
    const targetBlock = document.querySelector("#rec876494170 .t-slds__container");
    const movingBlock = document.querySelector("#rec876545440");

    if(targetBlock && movingBlock) {
        // Добавляем классы вместо inline-стилей
        targetBlock.classList.add('target-container');
        movingBlock.classList.add('moving-block');
        
        // Перемещаем блок
        targetBlock.appendChild(movingBlock);
    }
});
</script>
Страница с примером галереи https://piktografika.ru/vefir-uluchshennyy-slayder-dlya-saytov-na-tilde