
Я как всегда с фишкой для моб телефонов. Свайп окно всеми известно кто пользуется мобильными приложениями.
1) берем любой виджет заходив во вкладку шаблона и выбираем это ( см. скрин)
2 берем и вставляем этот код :
<style> /* Общие стили для затемняющего фона */ .adaptive-modal { display: none; position: fixed; z-index: 2000; left: 0; bottom: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.4); } /* Стили для мобильных устройств (по умолчанию) */ .adaptive-modal-container { position: fixed; left: 0; bottom: -100%; width: 100%; max-height: 95vh; /* Максимальная высота 90% экрана */ background-color: #fff; display: flex; flex-direction: column; box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.3); border-top-left-radius: 10px; border-top-right-radius: 10px; transition: bottom 0.2s ease, transform 0.05s ease; will-change: transform; } /* При открытии на мобильных: окно поднимается вверх */ .adaptive-modal.show .adaptive-modal-container { bottom: 0; } /* Шапка окна: фиксированная, без прокрутки */ .adaptive-modal-titlebar { position: relative; padding: 20px; padding-top: 40px; /* Отступ для полоски */ flex-shrink: 0; cursor: grab; } /* Прокручиваемая область с содержимым */ .adaptive-modal-body { padding: 0 20px 20px; overflow-y: auto; -webkit-overflow-scrolling: touch; flex: 1; } /* Кнопка закрытия (отображается в шапке) */ .adaptive-modal-close { position: absolute; top: 20px; right: 20px; cursor: pointer; font-size: 24px; } /* Полоска для приглашения к свайпу (видна только на мобильных) */ .adaptive-swipe-indicator { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); width: 50px; height: 5px; background-color: #ccc; border-radius: 3px; } /* Стили для десктопных устройств */ @media (min-width: 768px) { .adaptive-modal { justify-content: center; align-items: center; } .adaptive-modal-container { position: relative; max-height: none; max-width: 500px; width: 100%; border-radius: 10px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); bottom: auto; transform: none; transition: opacity 0.2s ease; opacity: 0; flex-direction: column; } .adaptive-modal.show .adaptive-modal-container { opacity: 1; } .adaptive-swipe-indicator { display: none; } .adaptive-modal-titlebar { padding-top: 20px; cursor: default; } } </style> <!-- Пример кнопки для открытия окна (если требуется) --> <!--<button id="openAdaptiveModal">Открыть окно</button>--> <div id="adaptiveModal" class="adaptive-modal"> <div class="adaptive-modal-container" id="adaptiveModalContainer"> <div class="adaptive-modal-titlebar" id="adaptiveModalTitlebar"> <div class="adaptive-swipe-indicator"></div> <span class="adaptive-modal-close"></span> </div> <div class="adaptive-modal-body" id="adaptiveModalBody"> {body} </div> </div> </div> <script> document.addEventListener("DOMContentLoaded", function() { const openModalButton = document.getElementById("openAdaptiveModal"); const modal = document.getElementById("adaptiveModal"); const modalContainer = document.getElementById("adaptiveModalContainer"); const modalBody = document.getElementById("adaptiveModalBody"); const titlebar = document.getElementById("adaptiveModalTitlebar"); const closeButton = document.querySelector(".adaptive-modal .adaptive-modal-close"); let startY = 0, translateY = 0, threshold = 200; // Порог для закрытия окна при свайпе по контейнеру // Переменные для свайпа по шапке let headerStartY = 0, headerTranslateY = 0, headerThreshold = 150; // Порог для свайпа по шапке (более чувствительный) /* Функция открытия модального окна */ function openModal() { if (window.innerWidth >= 768) { modal.style.display = "flex"; } else { modal.style.display = "block"; } document.body.style.overflow = "hidden"; setTimeout(() => { modal.classList.add("show"); }, 10); } /* Функция закрытия модального окна */ function closeModal() { modal.classList.remove("show"); document.body.style.overflow = ""; modalContainer.style.transform = ""; setTimeout(() => { modal.style.display = "none"; }, 200); } /* Сброс положения контейнера при свайпе по контейнеру */ function resetModalContent() { modalContainer.style.transition = "transform 0.05s ease"; modalContainer.style.transform = "translateY(0)"; setTimeout(() => { modalContainer.style.transition = "transform 0.05s ease"; }, 50); } /* Сброс положения контейнера при свайпе за шапку - минимальные задержки */ function resetHeaderSwipe() { modalContainer.style.transition = "transform 0.05s ease"; modalContainer.style.transform = "translateY(0)"; setTimeout(() => { modalContainer.style.transition = "transform 0.05s ease"; }, 50); } /* Обработчики для шапки (titlebar) для свайпа независимо от содержимого */ titlebar.addEventListener("touchstart", function(e) { titlebar.style.transition = "none"; headerStartY = e.touches[0].clientY; e.stopPropagation(); }); titlebar.addEventListener("touchmove", function(e) { const currentY = e.touches[0].clientY; headerTranslateY = currentY - headerStartY; if (headerTranslateY > 0) { modalContainer.style.transform = "translateY(" + headerTranslateY + "px)"; } e.stopPropagation(); }); titlebar.addEventListener("touchend", function(e) { if (headerTranslateY > headerThreshold) { closeModal(); } else { resetHeaderSwipe(); } headerStartY = 0; headerTranslateY = 0; e.stopPropagation(); }); /* Обработчики для области контейнера, если касание происходит вне шапки */ modalContainer.addEventListener("touchstart", function(e) { if (e.target.closest('.adaptive-modal-titlebar')) return; if (modalBody.scrollTop > 0) { startY = null; return; } modalContainer.style.transition = "none"; startY = e.touches[0].clientY; }); modalContainer.addEventListener("touchmove", function(e) { if (startY === null) return; const currentY = e.touches[0].clientY; translateY = currentY - startY; if (translateY > 0) { modalContainer.style.transform = "translateY(" + translateY + "px)"; } }); modalContainer.addEventListener("touchend", function() { if (startY === null) return; if (translateY > threshold) { closeModal(); } else { resetModalContent(); } startY = 0; translateY = 0; }); if (openModalButton) { openModalButton.addEventListener("click", openModal); } closeButton.addEventListener("click", closeModal); window.addEventListener("click", function(event) { if (event.target === modal) { closeModal(); } }); // Если окно должно открываться автоматически, можно вызвать openModal() здесь // openModal(); }); </script>
Ничего в нем не меняем {body} уже внутри
3 Сохраняем и размещаем свой виджет в любое место кроме хеда и футера ( просто в любое, все равно он скрыт)
С виджетом все!
Далее с помощью виджета или в тело шаблона вставляете код кнопки для вызова этого меню (Виджет с кнопкой можете размещать в любое месте, даже футер или хедер
<button id="openAdaptiveModal" class="btn btn-primary" style="margin-right: 5px"><svg class="icms-svg-icon w-16" fill="currentColor"><use href="/templates/modern/images/icons/solid.svg#ellipsis-h"></use></svg>Открыть окно</button>
Все! Кнопку размещай где угодно она вызовет виджет с этой страницы!
Что получаем ?
свайп адаптирован под любую длину информации, свайпается ( скрывается) пальцем вниз.
ВАЖНО!
Если вы хотите много виджетов запаковать таким образом то нужно прописывать уникальные классы в коде выше ( что бы не было конфликтов) к каждому виджету.
Так же можно кто разберется упаковать любой контент. Короче сделал все по госту приложений.
На настройки самого виджета это не влияет, как настроете так он и будет в свайп окне
Кому что надо доработать упаковать, пишите. За донатик помогу )
Благодарность можно 89819178831 сбер.
Эммм. И ведь пойдут делать это. Ну ёмоё, ну почитайте вы матчасть, что такое HTML страница, её структура и т.п. Куда вы вставляете в шаблон контейнера теги html, body, head. Они у вас есть на странице.
Ну да. Сочувствую кому вы будете помогать за донатик.
Ок больше не буду делиться ничем )
Все кто прочитал этот пост, не делайте, сломаете сайт.
Делайте только то что заложено движком.
Вместо критики лучше исправили и дали людям
Если вы про лишние теги типа HTML и body, то это не стоило такого комментария. Их просто можно удалить
С компа уберу эти теги. Тоже мне проблема
Триггернуло что вы на серьёзном пишите про благодарность и помощь за донат.
Я не говорю не делиться, делитесь. Вы себя позиционируете как человек, который за деньги может что-то сделать на веб сайт, т.е. вы вебмастер. Коммерческий вебмастер не может допускать такого рода ошибки.
Вы когда в чатгпт промпты пишите, уточняйте ему где вы хотите размещать код. Вот и эра ИИ получила человеческий фактор :)
Я достаточно даю людям на безвозмездной основе. А в вашем посте вы не просили помощи.
Теги убрал лишние. Причем тут gpt. Там больше моего чего его. Все лазят в интернете за поиском подсказок.
Я так и думал что вас зацепила именно помощь и фин поддержка ) меня тоже тригернуло. Это сплошь и рядом. Но, местные разработчики меня научили ценить свой труд и навык. )
Все не расстраивайтесь. Лояльней надо к тем кто учится программированию .
В не в агрессивной форме выражать свою не приязнь.
То что я предложил людям, работает? Работает! Это главное .
Я и не расстраиваюсь, не мой же пост :) Агрессию я точно в комментарий не закладывал.
Куда уж ещё лояльней. Пост на месте, на форуме вам отвечают, за постоянные орфографические ошибки молчат ;-) Вы правда не очень слушаете, а очень сложно помогать тому, кто помощь не принимает.
Понял принял, да, писать я не очень умею грамотно. Иногда и т9 помогает их допускать
Happy не обижайтесь, но критика про теги html, body правильная. Вам же не запрещают делиться полезными наработками. Просто примите положительную критику, поправьте код и будет всем хорошо от этого.
Я про теги согласен, у меня в проге они они автоматом открываются и закрываются при сохранении. скопировал не подумав. Уже убрал
Можно проще. Создать новую обертку для виджета — благо в системе есть такая возможность и использовать ее в любом виджете. Ну а кнопка — сделать для нее отдельный виджет, дел на 20 минут. Ну а в целом — хорошее практичное решение, просто немного не так поданное.
Подскажите пожалуйста на будущее или изменю пост как и где создаётся доп обёртка виджета ?
docs.instantcms.ru/dev/widgets#обертка-виджета
При выводе на страницу шаблон виджета оборачивается (помещается внутрь) еще одним шаблоном – оберткой (wrapper). Оберток может быть несколько, они хранятся в папке /templates/{тема}/widgets. Например, тема default имеет три доступные обертки:
Видео-туториал: Создание виджета
А вы об этом. Ну как я в посте об этом бы донес здесь? Если у каждого виджета своя структура, проще боди затолкать чем содержимое. А так я скинул универсальную верстку.
Вы не поняли, речь про обёртку. Это грубо говоря то, что вы прописали в «свой шаблон контейнера», только в файле, где можно подключить css/js файлы и доступен PHP.
Откройте указанные файлы и посмотрите что в них.