Исправлен мобильный виджет чата и добавлена кнопка закрытия
Этот коммит содержится в:
+57
-12
@@ -13,35 +13,62 @@
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.raspi-chat-button{position:fixed;right:20px;bottom:20px;z-index:2147483000;border:0;border-radius:999px;background:#172033;color:#fff;padding:14px 18px;font:700 14px system-ui;box-shadow:0 14px 35px rgba(0,0,0,.18);cursor:pointer}
|
||||
.raspi-chat-panel{position:fixed;right:20px;bottom:78px;z-index:2147483000;width:340px;max-width:calc(100vw - 40px);height:430px;display:none;flex-direction:column;border-radius:22px;overflow:hidden;background:#fff;box-shadow:0 22px 70px rgba(0,0,0,.22);font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
|
||||
.raspi-chat-button{position:fixed;right:18px;bottom:18px;z-index:2147483000;border:0;border-radius:999px;background:#172033;color:#fff;padding:13px 17px;font:700 14px system-ui;box-shadow:0 14px 35px rgba(0,0,0,.18);cursor:pointer;line-height:1}
|
||||
.raspi-chat-panel{position:fixed;right:18px;bottom:72px;z-index:2147483000;width:360px;max-width:calc(100vw - 32px);height:460px;max-height:calc(100vh - 96px);display:none;flex-direction:column;border-radius:22px;overflow:hidden;background:#fff;box-shadow:0 22px 70px rgba(0,0,0,.22);font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
|
||||
.raspi-chat-panel.open{display:flex}
|
||||
.raspi-chat-header{padding:16px;background:#172033;color:#fff;font-weight:800}
|
||||
.raspi-chat-messages{flex:1;padding:14px;overflow:auto;background:#f4f6fb;color:#172033;font-size:14px}
|
||||
.raspi-chat-message{margin:0 0 10px;padding:10px 12px;border-radius:14px;background:#fff;line-height:1.45}
|
||||
.raspi-chat-header{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:54px;padding:12px 14px 12px 16px;background:#172033;color:#fff;font-weight:800;line-height:1.2}
|
||||
.raspi-chat-title{display:flex;flex-direction:column;gap:2px;min-width:0}
|
||||
.raspi-chat-title strong{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.raspi-chat-title span{font-size:11px;font-weight:600;color:rgba(255,255,255,.68)}
|
||||
.raspi-chat-close{width:34px;height:34px;display:grid;place-items:center;border:0;border-radius:12px;background:rgba(255,255,255,.1);color:#fff;font:800 22px/1 system-ui;cursor:pointer;flex:0 0 auto}
|
||||
.raspi-chat-close:hover{background:rgba(255,255,255,.16)}
|
||||
.raspi-chat-messages{flex:1;padding:14px;overflow:auto;background:#f4f6fb;color:#172033;font-size:14px;overscroll-behavior:contain}
|
||||
.raspi-chat-message{margin:0 0 10px;padding:10px 12px;border-radius:14px;background:#fff;line-height:1.45;word-wrap:break-word;white-space:pre-wrap}
|
||||
.raspi-chat-message.operator{background:#dfe8ff;margin-left:18px}
|
||||
.raspi-chat-message.visitor{background:#fff;margin-right:18px}
|
||||
.raspi-chat-system{opacity:.7;font-size:12px;padding:4px 2px}
|
||||
.raspi-chat-form{display:flex;gap:8px;padding:12px;border-top:1px solid #e7ebf3}
|
||||
.raspi-chat-input{flex:1;border:1px solid #d7deea;border-radius:12px;padding:10px;font:14px system-ui}
|
||||
.raspi-chat-send{border:0;border-radius:12px;background:#4f6bff;color:#fff;padding:0 14px;font-weight:800;cursor:pointer}
|
||||
.raspi-chat-form{display:flex;gap:8px;padding:10px;border-top:1px solid #e7ebf3;background:#fff}
|
||||
.raspi-chat-input{flex:1;min-width:0;border:1px solid #d7deea;border-radius:12px;padding:10px;font:14px system-ui;outline:none}
|
||||
.raspi-chat-input:focus{border-color:#4f6bff;box-shadow:0 0 0 3px rgba(79,107,255,.12)}
|
||||
.raspi-chat-send{border:0;border-radius:12px;background:#4f6bff;color:#fff;min-width:44px;padding:0 14px;font-weight:800;cursor:pointer}
|
||||
@media (max-width: 560px){
|
||||
.raspi-chat-button{right:14px;bottom:14px;padding:13px 16px}
|
||||
.raspi-chat-panel{right:10px;left:10px;bottom:74px;width:auto;max-width:none;height:min(560px,calc(100vh - 92px));max-height:calc(100vh - 92px);border-radius:20px}
|
||||
.raspi-chat-header{min-height:50px;padding:10px 12px 10px 14px}
|
||||
.raspi-chat-close{width:38px;height:38px;border-radius:13px}
|
||||
.raspi-chat-messages{padding:12px;font-size:13px}
|
||||
.raspi-chat-message.operator{margin-left:10px}
|
||||
.raspi-chat-message.visitor{margin-right:10px}
|
||||
.raspi-chat-form{padding:9px}
|
||||
}
|
||||
@media (max-height: 560px){
|
||||
.raspi-chat-panel{top:10px;bottom:10px;height:auto;max-height:none}
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.className = 'raspi-chat-button';
|
||||
button.type = 'button';
|
||||
button.textContent = '💬 Чат';
|
||||
|
||||
const panel = document.createElement('section');
|
||||
panel.className = 'raspi-chat-panel';
|
||||
panel.setAttribute('aria-label', 'Чат поддержки');
|
||||
panel.innerHTML = `
|
||||
<div class="raspi-chat-header">StackWorks Support</div>
|
||||
<div class="raspi-chat-header">
|
||||
<div class="raspi-chat-title">
|
||||
<strong>StackWorks Support</strong>
|
||||
<span>Обычно отвечаем быстро</span>
|
||||
</div>
|
||||
<button class="raspi-chat-close" type="button" data-role="close" aria-label="Закрыть чат">×</button>
|
||||
</div>
|
||||
<div class="raspi-chat-messages" data-role="messages">
|
||||
<div class="raspi-chat-message operator">Здравствуйте! Чем можем помочь?</div>
|
||||
</div>
|
||||
<form class="raspi-chat-form" data-role="form">
|
||||
<input class="raspi-chat-input" data-role="input" placeholder="Ваше сообщение" autocomplete="off" />
|
||||
<button class="raspi-chat-send" type="submit">➤</button>
|
||||
<button class="raspi-chat-send" type="submit" aria-label="Отправить">➤</button>
|
||||
</form>
|
||||
`;
|
||||
|
||||
@@ -50,12 +77,29 @@
|
||||
const messages = panel.querySelector('[data-role="messages"]');
|
||||
const form = panel.querySelector('[data-role="form"]');
|
||||
const input = panel.querySelector('[data-role="input"]');
|
||||
const closeButton = panel.querySelector('[data-role="close"]');
|
||||
|
||||
let socket = null;
|
||||
let reconnectTimer = null;
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
panel.classList.toggle('open');
|
||||
function openChat() {
|
||||
panel.classList.add('open');
|
||||
button.style.display = 'none';
|
||||
setTimeout(() => input?.focus(), 120);
|
||||
}
|
||||
|
||||
function closeChat() {
|
||||
panel.classList.remove('open');
|
||||
button.style.display = '';
|
||||
}
|
||||
|
||||
button.addEventListener('click', openChat);
|
||||
closeButton.addEventListener('click', closeChat);
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Escape' && panel.classList.contains('open')) {
|
||||
closeChat();
|
||||
}
|
||||
});
|
||||
|
||||
function addMessage(text, type = 'visitor') {
|
||||
@@ -91,6 +135,7 @@
|
||||
|
||||
if (payload.type === 'operator_message') {
|
||||
addMessage(payload.message?.body || 'Новое сообщение от оператора', 'operator');
|
||||
openChat();
|
||||
}
|
||||
} catch {
|
||||
// ignore invalid frames
|
||||
|
||||
Ссылка в новой задаче
Block a user