
Привет, Хабр! Это Екатерина Саяпина, Product Owner платформы МТС Exolve. Сегодня покажу, как быстро добавить виджет обратного звонка на страницу, созданную с помощью MkDocs — статического генератора сайтов с уклоном в техническую документацию. Такое размещение виджета бывает нужно в справочных разделах сложных продуктов, где клиентам может потребоваться консультация или разъяснение каких-то технических моментов.
Для большей конкретики возьмем страницу с описанием S3 API вымышленного облачного провайдера — это типичный сценарий, где пользователю может потребоваться быстрая консультация специалиста.
Настройка MkDocs через Docker
Начнем с базовой установки MkDocs. Docker используется, чтобы упростить работу с зависимостями. В этом примере мы возьмем готовый образ squidfunk/mkdocs-material. Он содержит не только сам MkDocs, но и популярную тему Material, которая делает документацию красивой и удобной.
Одна команда — и вы получаете полностью настроенный проект с современным дизайном. Не нужно устанавливать Python, pip, возиться с виртуальным окружением — просто запустил контейнер, и все готово к работе:
mkdir cloudy-docs cd cloudy-docs docker run --rm -it -v ${PWD}:/docs squidfunk/mkdocs-material new .
После выполнения этой команды в текущей директории появится структура проекта MkDocs. Затем мы редактируем mkdocs.yml — это главный конфигурационный файл нашего проекта:
site_name: Cloudy Cloud Docs theme: name: material palette: primary: blue extra_javascript: - javascripts/exolve-callback.js
Тут мы задаем название сайта, выбираем тему Material и настраиваем синий цвет в качестве основного. Также мы добавляем ссылку на JavaScript-файл нашего виджета обратного звонка.
Файл конфигурации очень прост, но в реальных проектах он может быть гораздо более сложным, с настройками навигации, плагинов и т. д.
Создаем простую страницу документации
В этом примере мы создаем раздел на сайте с описанием S3 API, где можно найти информацию об основных операциях API для хранения данных в облаке. Использование Markdown упрощает работу с документацией — вы пишете текст с минимальной разметкой, а MkDocs превращает его в красивую HTML-страницу.
Содержимое нашей страницы для примера — в блоке ниже:
# Cloudy Cloud S3 API Простой и надежный сервис для хранения данных в облаке. ## Аутентификация Для доступа к API используйте ваши ключи доступа: curl -X GET https://s3.cloudy.cloud/buckets \ -H "Authorization: Bearer YOUR_API_KEY" ## Основные операции ### Создание бакета curl -X POST https://s3.cloudy.cloud/buckets \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "my-bucket", "region": "europe-west"}' ### Загрузка файла curl -X PUT https://s3.cloudy.cloud/buckets/my-bucket/file.txt \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: text/plain" \ --data-binary @file.txt ### Скачивание файла curl -X GET https://s3.cloudy.cloud/buckets/my-bucket/file.txt \ -H "Authorization: Bearer YOUR_API_KEY" ## Нужна помощь? <div id="exolve-callback-container"> Возникли вопросы по API? Наши инженеры готовы помочь! <div id="exolve-callback-button"></div> </div>
Посмотрите на последний раздел «Нужна помощь?». Здесь будет наша форма для обратного звонка — для этого мы и создаем контейнер с идентификатором exolve-callback-container.
Добавляем виджет
Создадим директорию для JavaScript-файлов и добавим скрипт для виджета:
mkdir -p docs/javascripts cd docs/javascripts touch exolve-callback.js
JavaScript-файл exolve-callback.js — это сердце нашего виджета. Он отвечает за создание кнопки, открытие модального окна при клике на нее, обработку формы и отправку данных в сервис МТС Exolve.
А теперь перейдем к созданию виджета. Код начинается с ожидания загрузки DOM. Затем ищем контейнер для кнопки обратного звонка:
document.addEventListener('DOMContentLoaded', function() { const callbackButton = document.getElementById('exolve-callback-button'); if (callbackButton) { const button = document.createElement('button'); button.textContent = 'Получить консультацию'; button.className = 'exolve-button'; button.style.backgroundColor = '#2196f3'; button.style.color = '#ffffff'; button.style.padding = '8px 16px'; button.style.border = 'none'; button.style.borderRadius = '4px'; button.style.cursor = 'pointer'; button.style.marginTop = '10px'; button.addEventListener('click', function() { createModal(); }); callbackButton.appendChild(button); }
Здесь создается затемненный фон (overlay) на весь экран, само модальное окно, его заголовок и форма.
Модальное окно размещается по центру с белым фоном и тенью:
function createModal() { const overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; overlay.style.zIndex = '1000'; overlay.style.display = 'flex'; overlay.style.justifyContent = 'center'; overlay.style.alignItems = 'center'; const modal = document.createElement('div'); modal.style.backgroundColor = '#fff'; modal.style.padding = '20px'; modal.style.borderRadius = '8px'; modal.style.maxWidth = '400px'; modal.style.width = '100%'; modal.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)'; const title = document.createElement('h3'); title.textContent = 'Запрос обратного звонка'; title.style.marginTop = '0'; title.style.color = '#333'; const form = document.createElement('form');
Следующий блок создает поля формы для ввода имени и телефона. Для каждого поля создается подпись (label) и само окно ввода (input) со стилями. Оба поля помечены как обязательные и заполняют всю ширину родительского элемента:
const nameLabel = document.createElement('label'); nameLabel.textContent = 'Ваше имя:'; nameLabel.style.display = 'block'; nameLabel.style.marginBottom = '5px'; nameLabel.style.fontWeight = 'bold'; const nameInput = document.createElement('input'); nameInput.type = 'text'; nameInput.required = true; nameInput.style.width = '100%'; nameInput.style.padding = '8px'; nameInput.style.marginBottom = '15px'; nameInput.style.boxSizing = 'border-box'; nameInput.style.border = '1px solid #ddd'; nameInput.style.borderRadius = '4px'; const phoneLabel = document.createElement('label'); phoneLabel.textContent = 'Ваш номер телефона:'; phoneLabel.style.display = 'block'; phoneLabel.style.marginBottom = '5px'; phoneLabel.style.fontWeight = 'bold'; const phoneInput = document.createElement('input'); phoneInput.type = 'tel'; phoneInput.placeholder = '+7 (___) ___-__-__'; phoneInput.required = true; phoneInput.style.width = '100%'; phoneInput.style.padding = '8px'; phoneInput.style.marginBottom = '15px'; phoneInput.style.boxSizing = 'border-box'; phoneInput.style.border = '1px solid #ddd'; phoneInput.style.borderRadius = '4px';
Далее создаются кнопки «отмена» и «отправить», которые размещаются в контейнере с гибкой разметкой. Затем вся структура собирается воедино: поля добавляются в форму, кнопки в контейнер, форма и заголовок в модальное окно, а оно в оверлей. Результат добавляется на страницу:
const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.justifyContent = 'space-between'; buttonContainer.style.marginTop = '20px'; const cancelButton = document.createElement('button'); cancelButton.textContent = 'Отмена'; cancelButton.type = 'button'; cancelButton.style.padding = '8px 16px'; cancelButton.style.backgroundColor = '#f5f5f5'; cancelButton.style.border = '1px solid #ddd'; cancelButton.style.borderRadius = '4px'; cancelButton.style.cursor = 'pointer'; const submitButton = document.createElement('button'); submitButton.textContent = 'Отправить'; submitButton.type = 'submit'; submitButton.style.padding = '8px 16px'; submitButton.style.backgroundColor = '#2196f3'; submitButton.style.color = '#fff'; submitButton.style.border = 'none'; submitButton.style.borderRadius = '4px'; submitButton.style.cursor = 'pointer'; form.appendChild(nameLabel); form.appendChild(nameInput); form.appendChild(phoneLabel); form.appendChild(phoneInput); buttonContainer.appendChild(cancelButton); buttonContainer.appendChild(submitButton); form.appendChild(buttonContainer); modal.appendChild(title); modal.appendChild(form); overlay.appendChild(modal); document.body.appendChild(overlay);
Теперь время добавить обработчики событий: отправки формы и закрытия модального окна при нажатии на кнопку «Отмена» или на затемненную область. При отправке проверяется заполнение полей, и если все в порядке, данные отправляются в сервис Exolve и показывается сообщение об успехе:
cancelButton.addEventListener('click', function() { document.body.removeChild(overlay); }); overlay.addEventListener('click', function(event) { if (event.target === overlay) { document.body.removeChild(overlay); } }); form.addEventListener('submit', function(event) { event.preventDefault(); const name = nameInput.value.trim(); const phone = phoneInput.value.trim(); if (!name || !phone) { alert('Пожалуйста, заполните все поля'); return; } sendDataToExolve(name, phone); document.body.removeChild(overlay); showSuccessMessage(); }); }
Теперь реализуем логику отправки данных. Функция sendDataToExolve очистит введенный телефон от нецифровых символов и проверит, загружен ли скрипт Exolve. Если нет, то она исправит это досадное недоразумение:
function sendDataToExolve(name, phone) { const cleanPhone = phone.replace(/\D/g, ''); if (typeof window.ExolveCallbackInit !== 'function') { const script = document.createElement('script'); script.src = 'https://widget.exolve.ru/callback/v1/js/button-loader.min.js'; script.async = true; document.head.appendChild(script); script.onload = function() { makeExolveRequest(name, cleanPhone); }; } else { makeExolveRequest(name, cleanPhone); } }
Структура данных для API в текущей версии просто выводится в консоль с помощью функции makeExolveRequest. В реальном проекте здесь должен быть код отправки запроса на сервер:
function makeExolveRequest(name, phone) { const requestData = { callback_resource_id: 1234, // Замените на ваш ID из личного кабинета number_code: phone, client_name: name, line_1: { destinations: [ { number: "74951234567" } // Замените на номер вашего оператора ] }, line_2: { destinations: [ { number: phone } ] } }; console.log('Отправляем данные в Exolve:', requestData); console.log('Запрос на обратный звонок отправлен'); }
Последняя функция — showSuccessMessage() — создает и показывает уведомление об успешной отправке запроса. Оно появляется в правом нижнем углу экрана как зеленый блок с текстом и автоматически исчезает через 5 секунд:
function showSuccessMessage() { const messageDiv = document.createElement('div'); messageDiv.style.position = 'fixed'; messageDiv.style.bottom = '20px'; messageDiv.style.right = '20px'; messageDiv.style.backgroundColor = '#4CAF50'; messageDiv.style.color = 'white'; messageDiv.style.padding = '16px'; messageDiv.style.borderRadius = '4px'; messageDiv.style.zIndex = '1000'; messageDiv.textContent = 'Спасибо! Наш специалист скоро свяжется с вами.'; document.body.appendChild(messageDiv); setTimeout(function() { document.body.removeChild(messageDiv); }, 5000); }
Проверка работы
Когда все готово, мы стартуем локальный сервер для разработки. Опять же используем Docker, чтобы не устанавливать ничего на компьютер. Команда запускает контейнер с MkDocs и открывает порт 8 000 для доступа к сайту.
docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material
Теперь мы можем открыть http://localhost:8000 в браузере и увидеть нашу страницу с виджетом:

Так можно все проверить перед публикацией на сайт.
Как работает виджет?

Когда пользователь нажимает на кнопку, виджет:
-
Пользователь нажимает на кнопку «Получить консультацию».
-
Открывается модальное окно с формой для ввода имени и номера телефона.
-
После заполнения формы и нажатия «Отправить» данные передаются в МТС Exolve.
-
Пользователь получает уведомление об успешной обработке запроса.
-
Сервис МТС Exolve инициирует звонок оператору и пользователю и соединяет их.
На серверной стороне это обрабатывается с помощью API МТС Exolve, которое принимает запрос в формате json:
{ "callback_resource_id": 1234, "number_code": "79991234567", "client_name": "Иван Петров", "line_1": { "destinations": [ { "number": "74951234567" } ] }, "line_2": { "destinations": [ { "number": "79991234567" } ] } }
Финальная сборка
Когда все готово и протестировано, можно собрать статическую версию документации для публикации. Опять же мы используем Docker:
docker run --rm -it -v ${PWD}:/docs squidfunk/mkdocs-material build
Команда build создает полностью статический сайт, который можно разместить на любом хостинге. Готовые файлы появляются в директории site/. Это удобно, так как вам не нужно устанавливать никакое серверное программное обеспечение — просто загрузите файлы, и все готово.
Подружить виджет обратного звонка в MkDocs достаточно легко. Этот пример показывает, что такой элемент можно встроить практически в любую веб-страницу: будь то документация, интернет-магазин или корпоративный сайт.
На этом все! Если у вас остались вопросы по интеграции виджета в ваши проекты, задавайте их в комментариях.
ссылка на оригинал статьи https://habr.com/ru/articles/900676/
Добавить комментарий