Задать вопрос
  • Как указать путь в JS к json-файлу, чтобы он учитывался при сборке (parcel js)?

    @catch-a-chalk
    Попробуйте импортировать извне, чтобы json включался в сборку:
    import data from './js/data.json';
    
    function p() {
        o.loadAnimation({
            container: h,
            renderer: "canvas",
            loop: !0,
            autoplay: !0,
            animationData: data
        });
    }


    Или если нужно, чтобы он оставался отдельным файлом:
    function p() {
        const jsonPath = new URL('./js/data.json', import.meta.url).href;
        
        o.loadAnimation({
            container: h,
            renderer: "canvas",
            loop: !0,
            autoplay: !0,
            path: jsonPath
        });
    }


    Успехов!
    Ответ написан
    Комментировать
  • Что не так в этой вёрстке с grid для Safari?

    @catch-a-chalk
    Задать фиксированную величину - неплохая идея, но нужно тогда предусмотреть переполнение контентом внутри карточки и прописать в стилях скролл.

    У меня была схожая проблема: внутри флекс-контейнера изображение выбивало текст за пределы блока (и тоже только на сафари). Помогло свойство для изображения max-height: inherit;. А так как флекс-блок был внутри грид-сетки, высота подогналась по родителю.
    Ответ написан
    Комментировать
  • Почему не отображается первый слайдер?

    @catch-a-chalk
    Привет
    1. Прозвучит смешно, но нужно проверить подключение библиотеки.
    2. Потом проверить вложенность HTML и CSS классов, бывало, что опечатка и все.
    3. Попробуйте отключить loop и проверить, отображается ли первый слайд.
    4. Проверьте кастомную логику (slideChange и swiperInit).
    5. Используйте DevTools для диагностики.
    Ответ написан
    Комментировать
  • Как выполнить ëфикацию без сторонних библиотек?

    @catch-a-chalk
    В общем, если все буквы «е» без исключения, то так:

    function replaceE(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            node.textContent = node.textContent.replace(/е/g, 'ё').replace(/Е/g, 'Ё');
        } else {
            node.childNodes.forEach(replaceE);
        }
    }


    А если учитывать контекст, то нашел на просторах модуль (сам не пробовал): https://github.com/e2yo/eyo-kernel
    Ответ написан
    Комментировать
  • Как я могу создать такую логику?

    @catch-a-chalk
    Привет, стоит ввести еще одну функцию positionMarkerдля такой задачи:

    const items = [
        { name: "100 000", reward: "100000_sr", chance: 5 },
        { name: "VIP (14 дней)", reward: "14_vipsr", chance: 3 },
        { name: "1000 Алмазов", reward: "1000_az", chance: 2 },
        { name: "75 000 ", reward: "75000_sr", chance: 10 },
        { name: "VIP SILVER (7 дней)", reward: "7_sl", chance: 8 },
        { name: "500 Алмазов", reward: "500_az", chance: 7 },
        { name: "1000 Пыли", reward: "1000_ds", chance: 6 },
        { name: "25 000 ", reward: "25000_sr", chance: 15 },
        { name: "200 Алмазов", reward: "200_az", chance: 15 },
        { name: "300 Пыли", reward: "300_ds", chance: 15 },
        { name: "Ускорение (3 lvl)", reward: "3_boost", chance: 10 },
        { name: "Улучшение (3 lvl)", reward: "3_imp", chance: 10 },
        { name: "VIP SILVER (2 дня)", reward: "2_sl", chance: 10 },
        { name: "10 000 ", reward: "10000_sr", chance: 20 },
        { name: "5 000 ", reward: "5000_sr", chance: 20 },
        { name: "100 Алмазов", reward: "100_az", chance: 20 },
        { name: "Ускорение (2 lvl)", reward: "2_boost", chance: 20 }
    ];
    
    const caseContainer = document.getElementById("caseContainer");
    const scrollingItems = document.getElementById("scrollingItems");
    const resultText = document.getElementById("resultText");
    const openCaseButton = document.getElementById("openCaseButton");
    const marker = document.getElementById("marker");
    let populatedItems = []; // Массив для хранения созданных предметов
    let winningIndex = 0; // Индекс выигрышного предмета
    
    function populateItems() {
        for (let i = 0; i < 151; i++) { // Создаем 151 предмет
            const item = items[i % items.length]; // Используем элементы из массива
            const div = document.createElement("div");
            div.className = "item";
            div.innerText = item.name;
            scrollingItems.appendChild(div);
            populatedItems.push(item); // Сохраняем предмет в массив
        }
    }
    
    function animateScroll(duration) {
        const itemWidth = scrollingItems.children[0].offsetWidth; // Ширина одного предмета
        const totalItems = scrollingItems.children.length;
    
        // Позиция, на которую нужно прокрутить, чтобы выигрышный элемент оказался под стрелкой
        const targetPosition = (winningIndex * itemWidth) - (caseContainer.offsetWidth / 2) + (itemWidth / 2); // Центрируем выигрышный элемент
        const scrollWidth = totalItems * itemWidth; // Общая ширина прокрутки
        const startTime = performance.now();
    
        function scrollAnimation(currentTime) {
            const elapsedTime = currentTime - startTime;
            const progress = Math.min(elapsedTime / duration, 1);
            const easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
    
            const easeProgress = easeInOutQuad(progress);
            const currentPosition = -scrollWidth * easeProgress + targetPosition; // Прокручиваем к целевой позиции
            scrollingItems.style.marginLeft = `${currentPosition}px`;
    
            if (progress < 1) {
                requestAnimationFrame(scrollAnimation);
            } else {
                // После завершения анимации, показываем выигрышный элемент
                showWinningItem(); // Показываем выигрышный элемент
                positionMarker(); // Позиционируем маркер над выигрышным элементом
            }
        }
    
        requestAnimationFrame(scrollAnimation);
    }
    
    function showWinningItem() {
        const winningItem = populatedItems[winningIndex]; // Получаем выигрышный предмет
        resultText.innerText = `Вы выиграли: ${winningItem.name}`;
    
        // Изменяем текст выигрышного предмета в scrollingItems
        const winningElement = scrollingItems.children[winningIndex];
        winningElement.classList.add("winning-item"); // Добавляем класс для стилей
        winningElement.innerText = winningItem.name; // Обновляем текст
    }
    
    function positionMarker() {
        // Ширина одного предмета
        const itemWidth = scrollingItems.children[0].offsetWidth; 
        // Центрируем маркер над выигрышным элементом
        const markerPosition = (winningIndex * itemWidth) - (caseContainer.offsetWidth / 2) + (itemWidth / 2); 
        // Устанавливаем позицию маркера
        marker.style.left = `${markerPosition}px`; 
    }
    
    openCaseButton.addEventListener("click", () => {
        // Очищаем текст результата
        resultText.innerText = ""; 
        // Очищаем массив предметов
        populatedItems = []; 
        // Очищаем элементы прокрутки
        scrollingItems.innerHTML = ""; 
        // Заполняем предметами при загрузке страницы
        populateItems(); 
    
        // Выбираем случайный индекс выигрышного предмета
        // Случайный индекс в пределах массива items
        winningIndex = Math.floor(Math.random() * populatedItems.length);
        // Запускаем анимацию прокрутки (уменьшено время)
        animateScroll(2000); 
    });


    И ее же добавляем в анимацию скролла.
    Ответ написан
    Комментировать
  • Как Clamp влияет на производительность, если его везде использовать?

    @catch-a-chalk
    Привет! Если вкратце, то использование математических функций типа clamp(), calc(), sin() и других действительно нагружают браузер.

    Если чуть подробнее, то затрачивается больше ресурсов при рендеринге, а при большом количестве стилей с функциями гарантированно будет доп. нагрузка, плюс легче запутаться при отладке. Короче, есть ли смысл заморачиваться с выбором между удобством и производительностью? @media и лайтхаус в помощь :)
    Ответ написан
    Комментировать
  • Как отключить "Reader mode" в Safari на IOS?

    @catch-a-chalk
    Привет, сталкивался с похожей проблемой. Сафари активирует режим чтения, если считает страницу чисто текстовой. Через метаданные или доп. теги можно попробовать его перехитрить, но тестировать все равно придется через разные версии Сафари (есть сервисы типа https://www.browserstack.com/test-on-safari-browser, но в бесплатной версии набор скудный).

    Мета:
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">


    В HTML «усложняем» разметку:
    <div style="display: none;">
        <iframe src="about:blank" width="1" height="1"></iframe>
    </div>
    Ответ написан
    Комментировать
  • Ошибка Uncaught TypeError: Cannot read properties of undefined (reading 'find'). Как можно поправить?

    @catch-a-chalk
    function slideChange(swiper) {
        const activeSlide = swiper.slides[swiper.activeIndex];
        const contentIndex = activeSlide.getAttribute('data-swiper-slide-index');
    
        const content = contentFullsizeEls[contentIndex];
    
        if (!content) return;
    
        if (state.bottomContent) {
            state.bottomContent.classList.remove("hero__content--bottom");
            state.bottomContent.classList.add("hero__content--hidden");
        }
    
        if (state.topContent) {
            state.topContent.classList.remove("hero__content--top");
            state.topContent.classList.add("hero__content--hidden");
        }
    
        state.bottomContent = state.topContent;
        state.topContent = content;
    
        const slidetRect = swiper.slides[swiper.activeIndex].getBoundingClientRect();
        const parentRect = heroEl.getBoundingClientRect();
    
        content.style.transition = "none";
        content.style.left = slidetRect.left - parentRect.left + "px";
        content.style.top = slidetRect.top - parentRect.top + "px";
        content.style.width = slidetRect.width + "px";
        content.style.height = slidetRect.height + "px";
        content.style.borderRadius = "var(--border-radius, 0)";
    
        content.getBoundingClientRect();
    
        content.classList.remove("hero__content--hidden");
        content.classList.add("hero__content--top", "hero__content--grow");
    
        content.style.transition = "";
        content.style.left = "";
        content.style.top = "";
        content.style.width = "";
        content.style.height = "";
        content.style.borderRadius = "";
    
        const onShowTextEnd = (event) => {
            if (event.target !== event.currentTarget) {
                event.currentTarget.removeEventListener("transitionend", onShowTextEnd);
            }
        };
    
        const onGrowEnd = (event) => {
            event.currentTarget.classList.remove("hero__content--grow");
            event.currentTarget.classList.add("hero__content--show-text");
            event.currentTarget.addEventListener("transitionend", onShowTextEnd);
        };
    
        content.addEventListener("transitionend", onGrowEnd, { once: true });
    }
    Ответ написан
    Комментировать
  • Динамическое изменение value формы в js - как устранить ошибку дублирования?

    @catch-a-chalk
    Приветствую. Нужно проверку добавить, есть этот текст в текущем состоянии или нет:
    if (document.getElementById("mess").value == 'Курьер') {
        const giftMessField = document.getElementById("gift_mess");
        const userText = giftMessField.value;
        const addedText = 'добавленный текст ';
    
        if (!userText.startsWith(addedText)) {
            giftMessField.value = addedText + userText;
        }
    }
    Ответ написан
    Комментировать
  • Как добавлять класс при клике только 2 раза?

    @catch-a-chalk
    Привет,
    const mainBlocks = document.querySelectorAll('.main-block');
    const maxActive = 2; // Максимальное количество активных элементов
    
    mainBlocks.forEach(block => {
        block.addEventListener("click", function () {
            const id = block.dataset.id;
            const contentBlocks = document.querySelectorAll(`.other-block[data-id='${id}']`);
    
            // Если элемент уже активен, деактивируем его
            if (block.classList.contains('_active')) {
                block.classList.remove('_active');
                contentBlocks.forEach(contentBlock => contentBlock.classList.remove('_active'));
            } else {
                // Проверяем, сколько элементов уже активно
                const activeBlocks = document.querySelectorAll('.main-block._active');
                if (activeBlocks.length >= maxActive) {
                    // Деактивируем первый активный элемент
                    const firstActive = activeBlocks[0];
                    firstActive.classList.remove('_active');
                    const firstId = firstActive.dataset.id;
                    document.querySelectorAll(`.other-block[data-id='${firstId}']`).forEach(contentBlock => contentBlock.classList.remove('_active'));
                }
    
                // Активируем текущий элемент
                block.classList.add('_active');
                contentBlocks.forEach(contentBlock => contentBlock.classList.add('_active'));
            }
        });
    });
    Ответ написан
    Комментировать
  • Как понять откуда лишнее пространство у страницы?

    @catch-a-chalk
    Можно попробовать инспектировать пространство через курсор в панели разработчика (Ctrl + U). Еще может быть такое, что есть где-то флексы или гриды (чаще хедер и футер), которые сдвигают страницу за счет дочерних элементов с паддингами.
    Ответ написан
    Комментировать
  • Какой сервис выбрать для структуризации идей?

    @catch-a-chalk
    Notion. В отличие от Obsidian у него есть синхронизация с разными устройствами по привязке к профилю, плюс выглядит приятнее, много функций по типу помощника ИИ.
    Ответ написан
    Комментировать