Дата: Воскресенье, 04.01.2026, 10:12 | Сообщение # 1 |
|
Написал: Узнаваемый
Автор темы
Мурчанн
не в сети
Сообщений: 162
Назначение модуля Этот модуль предназначен для удобного и современного интерфейса создания публикаций на сайте, работающем на платформе uCoz. Он позволяет авторизованным пользователям создавать посты, включающие: 1. Заголовок статьи 2. Категорию публикации 3. Краткое описание (с возможностью вставки смайлов) 4. Основной текст статьи (тоже с поддержкой смайлов)Модуль работает через попап-окно, которое появляется поверх основного контента, не перезагружая страницу. Структура HTML Обертка сайта Код
<div id="siteWrapper" style="position: relative; max-width: 1200px; margin: 0 auto; background: #f5f5f5; min-height: 100vh;">
Ограничивает ширину сайта до 1200px, центрирует контент и задает минимальную высоту.Кнопка открытия формы Код
<a id="openArticleForm">💬 Send Message</a>
Позиционируется сбоку страницы и при наведении визуально увеличивается. При клике открывает форму публикации.Попап и оверлей Код
<div id="publOverlay"></div> <div id="publModal"></div>
1. #publOverlay затемняет фон страницы. 2. #publModal — это само модальное окно с формой. 3. Форма публикации 4. Заголовок (#p_title) 5. Категория (#p_cat) 6. Краткое описание (#p_brief) с кнопкой и панелью смайлов 7. Основной текст (#p_text) с кнопкой и панелью смайлов 8. Кнопка отправки (#p_send) 9. Статус отправки (#p_status)CSS стилизация 1. Модальное окно имеет плавную анимацию появления (transform: translateY/translateX) и тень, чтобы выделяться на фоне сайта. 2. Кнопки имеют градиентную заливку, плавные hover-эффекты и скругленные углы, что делает интерфейс современным. 3. Поля формы и textarea имеют фокус-эффект с подсветкой границ. 4. Статус публикации (#p_status) подсвечивается зелёным при успехе и красным при ошибке с эффектом пульса.Работа JavaScript Открытие и закрытие формы Код
$('#openArticleForm').on('click', function(){ $('#publOverlay').fadeIn(200); $('#publModal').css('transform','translateX(0)'); });
Форма появляется плавно при клике на кнопку. Закрытие формы реализовано как по клику на крестик, так и по клику на оверлейКод
$('#closePubl, #publOverlay').on('click', function(e){ ... });
Поддержка смайлов Два текстовых поля (#p_brief и #p_text) имеют кнопку смайлов, при клике на которую открывается панель с набором смайлов. При клике на смайл он вставляется в текущее место курсора в textarea. Панель закрывается при клике вне её области.Отправка статьи на сервер Код
$('#p_send').on('click', function(){ // проверка заполнения полей // получение ssid из скрытого iframe // POST-запрос на /publ });
Скрипт проверяет, что все обязательные поля заполнены. 1. Из скрытого iframe извлекается ssid — уникальный идентификатор сессии uCoz для безопасного выполнения POST-запроса. 2. Статья отправляется на сервер через AJAX ($.post), без перезагрузки страницы.После успешной отправки: 1. Выводится сообщение об успехе 2. Форма закрывается через секунду 3. Страница обновляется для отображения новой публикацииВ случае ошибки выводится красный статус с подсветкой. Поддержка авторизации Форма доступна только авторизованным пользователям. Скрытый iframeКод
<iframe id="ssidFrame" src="/publ/1-0-0-0-1" style="display:none;"></iframe>
Используется для безопасного получения ssid для POST-запроса. Плавная анимация и UX Hover-эффекты, анимация пульса для статуса, плавное открытие/закрытие попапа создают современный и комфортный интерфейс.Как работает весь модуль шаг за шагом Пользователь кликает на кнопку Send Message - форма плавно появляется.Пользователь заполняет поля: Заголовок, категория, краткое описание, текст статьи При желании добавляет смайлы через панели Пользователь нажимает Создать запись Скрипт проверяет заполненность полейИз скрытого iframe извлекается ssid для идентификации сессии Выполняется AJAX-запрос на сервер /publСервер обрабатывает публикацию: Если успешна - форма закрывается, статус зелёный, страница обновляется Если ошибка - отображается сообщение об ошибке краснымПанель смайлов закрывается автоматически при клике вне её области. Современный инструмент для создания публикаций на uCoz. Код
<!-- ОБЕРТКА ВСЕГО САЙТА --> <div id="siteWrapper" style="position: relative; max-width: 1200px; margin: 0 auto; background: #f5f5f5; min-height: 100vh;"> <style> /* ===== Кнопка открытия формы ===== */ #openPublForm { position: fixed; right: 20px; bottom: 20px; z-index: 99999; padding: 10px 20px; /* чуть меньше */ background: linear-gradient(135deg,#4c75a3,#3b5998); color: #fff; font-size: 14px; /* меньше шрифт кнопки */ font-weight: 600; border: none; border-radius: 50px; cursor: pointer; box-shadow: 0 6px 16px rgba(0,0,0,.35); transition: all 0.3s ease; } #openPublForm:hover { transform: scale(1.05); box-shadow: 0 10px 28px rgba(0,0,0,.45); } /* ===== Overlay (фон) ===== */ #publOverlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: none; /* скрыт по умолчанию */ z-index: 999998; } /* ===== Модальное окно ===== */ #publModal { position: fixed; right: 20px; bottom: 20px; width: 280px; /* немного уже, чтобы выглядело компактнее */ background: #fff; border-radius: 12px; box-shadow: 0 12px 30px rgba(0,0,0,0.35); transform: translateY(100%); transition: transform 0.4s ease; overflow: hidden; display: flex; flex-direction: column; z-index: 999999; } /* ===== Header ===== */ .publHeader { background: linear-gradient(135deg,#4c75a3,#3b5998); color: #fff; padding: 12px; /* чуть меньше */ display: flex; justify-content: space-between; font-size: 14px; /* меньше шрифт заголовка */ font-weight: 600; } .publHeader span { cursor: pointer; transition: transform 0.2s ease; } .publHeader span:hover { transform: rotate(90deg); } /* ===== Body ===== */ .publBody { padding: 15px; /* уменьшено padding */ display: flex; flex-direction: column; gap: 10px; /* меньше отступ между полями */ align-items: flex-start; text-align: left; font-size: 13px; /* общий шрифт для текста формы */ } /* Labels */ .publBody label { font-weight: 500; margin-bottom: 3px; width: 100%; text-align: left; } /* Inputs, selects, textarea */ .publBody input, .publBody select, .publBody textarea { width: 100%; padding: 8px; /* меньше padding */ border-radius: 6px; border: 1px solid #dce1e6; outline: none; transition: all 0.3s ease; font-size: 13px; /* уменьшен шрифт текста в полях */ font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif; text-align: left; } .publBody input:focus, .publBody select:focus, .publBody textarea:focus { border-color: #4c75a3; box-shadow: 0 0 8px rgba(76,117,163,0.3); } /* ===== Button отправки ===== */ #p_send { width: 100%; padding: 20px 0; /* чуть ниже и не слишком высоко */ margin-top: 5px; /* отступ от полей */ background: linear-gradient(135deg,#4c75a3,#3b5998); color: #fff; font-size: 13px; font-weight: 600; border: none; border-radius: 5px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 14px rgba(76,117,163,0.35); } #p_send:hover { transform: scale(1.00); box-shadow: 0 9px 24px rgba(76,117,163,0.45); } /* ===== Статус сообщения ===== */ #p_status { margin-top: 8px; font-size: 16px; /* больше шрифт */ font-weight: 600; /* более жирный */ min-height: 20px; text-align: center; transition: all 0.3s ease; } /* Цвета для статуса */ #p_status.error { color: #e74c3c; /* красный */ animation: pulse 0.6s ease-in-out; } #p_status.success { color: #2ecc71; /* зелёный */ animation: pulse 0.6s ease-in-out; } /* Пульс для внимания */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } /* ===== Анимация показа ===== */ #publOverlay.active { display: block; } #publModal.active { transform: translateY(0); } </style> <!-- Кнопка "Send Message" --> <a href="javascript:void(0);" id="openArticleForm" style=" position: absolute; right: -450px; top: 50%; background: #3b5998; color: #fff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 14px; font-weight: 500; padding: 11px 30px; border-radius: 8px 0 0 8px; text-decoration: none; box-shadow: 0 6px 16px rgba(76,117,163,0.45); transition: all 0.3s ease; z-index: 9999; " onmouseover=" this.style.background='#3f6691'; this.style.paddingRight='115px'; this.style.boxShadow='0 10px 24px rgba(76,117,163,0.55)'; " onmouseout=" this.style.background='#3b5998'; this.style.paddingRight='30px'; this.style.boxShadow='0 6px 16px rgba(76,117,163,0.45)'; " > 💬 Send Message </a> </div> <!-- показываем только авторизованным --> <?if($USER_ID$>0)?> <!-- POPUP Overlay --> <div id="publOverlay" style=" position: fixed; inset: 0; background: rgba(0,0,0,.6); display: none; align-items: center; justify-content: center; z-index: 999999; "> <div id="publModal" style=" width: 500px; background: #fff; border-radius: 5px; transform: translateX(100%); transition: transform 0.3s ease; "> <div class="publHeader" style=" background: #4c75a3; color: #fff; padding: 14px; display: flex; justify-content: space-between; "> Закрепить пост на стене <span id="closePubl" style="cursor:pointer;">✖</span> </div> <!-- СТАТУС СООБЩЕНИЯ ВВЕРХУ --> <div id="p_status"></div> <div class="publBody" style="padding:14px;"> <label>Заголовок *</label> <input type="text" id="p_title"> <label>Категория *</label> <select id="p_cat"> <option value="1">Стена</option> </select> <!-- ===== Краткое описание с кнопкой смайлов ===== --> <div class="publBody" style="padding:0px; position: relative; margin-bottom:10px;"> <label>Краткое описание *</label> <textarea id="p_brief" style="height:100px; width:475px; padding-right:5px;"></textarea> <!-- Кнопка смайлов --> <button type="button" id="emojiBtnBrief" style=" position: absolute; right: 5px; top: 95px; /* позиция кнопки по высоте textarea */ width: 28px; height: 28px; background: #f5f5f5; border: 1px solid #ccc; border-radius: 50%; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; ">😊</button> <!-- Панель смайлов --> <div id="emojiPanelBrief" style=" position: absolute; right: 0; top: 10px; width: 220px; max-height: 250px; overflow-y: auto; background: #fff; border: 1px solid #ccc; border-radius: 6px; display: none; padding: 5px; box-shadow: 0 5px 15px rgba(0,0,0,0.2); z-index: 10000; display: flex; flex-wrap: wrap; gap: 4px; "> <!-- Сюда скрипт вставит все смайлы --> </div> </div> <script> $(document).ready(function(){ const textareaBrief = $('#p_brief'); const emojiBtnBrief = $('#emojiBtnBrief'); const emojiPanelBrief = $('#emojiPanelBrief'); // массив смайлов (юкоЗовские стандартные) const emojis = [ '😀','😁','😂','🤣','😃','😄','😅','😆','😉','😊','😋','😎','😍','😘', '😗','😙','😚','🙂','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣', '😥','😮','🤐','😯','😪','😫','🥱','😴','😌','😛','😜','😝','🤤','😒', '😓','😔','😕','🙃','🤑','😲','☹️','🙁','😖','😞','😟','😤','😢','😭', '😦','😧','😨','😩','🤯','😬','😰','😱','🥵','🥶','😳','🤪','😵','🥴','😠','😡' ]; // добавляем смайлы в панель emojis.forEach(e=>{ emojiPanelBrief.append(`<span class="emojiItem" style="cursor:pointer; font-size:16px;">${e}</span>`); }); // показать/скрыть панель emojiBtnBrief.on('click', function(e){ e.stopPropagation(); emojiPanelBrief.toggle(); }); // клик по смайлу — вставка emojiPanelBrief.on('click', '.emojiItem', function(){ const emoji = $(this).text(); const start = textareaBrief[0].selectionStart; const end = textareaBrief[0].selectionEnd; const text = textareaBrief.val(); textareaBrief.val(text.substring(0,start) + emoji + text.substring(end)); textareaBrief[0].selectionStart = textareaBrief[0].selectionEnd = start + emoji.length; textareaBrief.focus(); }); // закрываем панель, если клик вне $(document).on('click', function(e){ if(!$(e.target).closest('#emojiPanelBrief, #emojiBtnBrief').length){ emojiPanelBrief.hide(); } }); }); </script> <!-- ===== Текстовая форма с кнопкой смайлов ===== --> <div class="publBody" style="padding:0px; position: relative;"> <label>Текст статьи *</label> <textarea id="p_text" style="height:100px; width:475px; padding-right:5px;"></textarea> <!-- Кнопка смайлов --> <button type="button" id="emojiBtn" style=" position: absolute; right: 5px; top: 95px; width: 28px; height: 28px; background: #f5f5f5; border: 1px solid #ccc; border-radius: 50%; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; ">😊</button> <!-- Панель смайлов --> <div id="emojiPanel" style=" position: absolute; right: 0; top: 10px; width: 220px; max-height: 250px; overflow-y: auto; background: #fff; border: 1px solid #ccc; border-radius: 6px; display: none; padding: 5px; box-shadow: 0 5px 15px rgba(0,0,0,0.2); z-index: 10000; display: flex; flex-wrap: wrap; gap: 4px; "> <!-- Сюда скрипт вставит все смайлы --> </div> </div> <script> $(document).ready(function(){ const textarea = $('#p_text'); const emojiBtn = $('#emojiBtn'); const emojiPanel = $('#emojiPanel'); // массив смайлов (юкоЗовские стандартные) const emojis = [ '😀','😁','😂','🤣','😃','😄','😅','😆','😉','😊','😋','😎','😍','😘', '😗','😙','😚','🙂','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣', '😥','😮','🤐','😯','😪','😫','🥱','😴','😌','😛','😜','😝','🤤','😒', '😓','😔','😕','🙃','🤑','😲','☹️','🙁','😖','😞','😟','😤','😢','😭', '😦','😧','😨','😩','🤯','😬','😰','😱','🥵','🥶','😳','🤪','😵','🥴','😠','😡' ]; // добавляем смайлы в панель emojis.forEach(e=>{ emojiPanel.append(`<span class="emojiItem" style="cursor:pointer; font-size:16px;">${e}</span>`); }); // показать/скрыть панель emojiBtn.on('click', function(e){ e.stopPropagation(); emojiPanel.toggle(); }); // клик по смайлу — вставка emojiPanel.on('click', '.emojiItem', function(){ const emoji = $(this).text(); const start = textarea[0].selectionStart; const end = textarea[0].selectionEnd; const text = textarea.val(); textarea.val(text.substring(0,start) + emoji + text.substring(end)); textarea[0].selectionStart = textarea[0].selectionEnd = start + emoji.length; textarea.focus(); }); // закрываем панель, если клик вне $(document).on('click', function(e){ if(!$(e.target).closest('#emojiPanel, #emojiBtn').length){ emojiPanel.hide(); } }); }); </script> <button id="p_send">Создать запись</button> </div> </div> </div> <?endif?> <!-- для перехвата ssid --> <iframe id="ssidFrame" src="/publ/1-0-0-0-1" style="display:none;"></iframe> <script> $(document).ready(function(){ const out = $('#p_status'); // элемент статуса // ===== Открытие формы ===== $('#openArticleForm').on('click', function(){ $('#publOverlay').fadeIn(200); $('#publModal').css('transform','translateX(0)'); out.text('').removeClass('error success'); // очищаем статус при открытии }); // ===== Закрытие формы ===== $('#closePubl, #publOverlay').on('click', function(e){ if(e.target.id==='closePubl' || e.target.id==='publOverlay'){ $('#publModal').css('transform','translateX(100%)'); setTimeout(()=>$('#publOverlay').fadeOut(200),300); out.text('').removeClass('error success'); } }); // ===== Отправка статьи ===== $('#p_send').on('click', function(){ const title = $('#p_title').val().trim(); const cat = $('#p_cat').val(); const brief = $('#p_brief').val().trim(); const text = $('#p_text').val().trim(); out.text('').removeClass('error success'); // очищаем старый статус // Проверка полей if(!title || !cat || !brief || !text){ out.addClass('error').text('❌ Заполните все поля'); return; } // Получаем ssid из iframe let doc = document.getElementById('ssidFrame').contentWindow.document; let ssidInput = doc.querySelector('input[name="ssid"]'); if(!ssidInput){ out.addClass('error').text('❌ ssid НЕ НАЙДЕН'); return; } // ===== POST на сервер ===== $.post('/publ', { a: 12, ssid: ssidInput.value, ocat: cat, title: title, brief: brief, edttbrief: 2, message: text, edttmessage: 2 }) .done(function(res){ if(/НЕ СОЗДАНА|error|ошиб/i.test(res)){ out.addClass('error').text('❌ uCoz: СТАТЬЯ НЕ СОЗДАНА'); } else { out.addClass('success').text('✅ Статья ОТПРАВЛЕНА!'); // ===== Закрываем форму через 1 сек ===== setTimeout(()=>{ $('#publModal').css('transform','translateX(100%)'); $('#publOverlay').fadeOut(200); $('#p_title,#p_text,#p_brief,#p_cat').val(''); location.reload(); // перезагрузка страницы },1000); } }) .fail(()=>{ out.addClass('error').text('❌ POST НЕ ПРОШЁЛ'); }); }); }); </script>
Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.