122131231212
🧩 Syntax:
// ==UserScript==
// @name Lolz Transparent Chat — v2.9.10 (glass restore + mobile header H-scroll + buttons safe)
// @namespace http://tampermonkey.net/
// @version 2.9.10
// @description Прозрачный чат (окно и /chatbox/) + корректные рамки упоминаний + фиксы кнопок + крестики + мобильный H-скролл шапки. Прозрачность восстановлена во всех контейнерах.
// @match https://lzt.market/*
// @match https://lolz.live/*
// @match https://zelenka.guru/*
// @grant none
// @license MIT
// ==/UserScript==
(() => {
'use strict';
const BLUR_PX = 12;
const ALPHA_GLASS = 0.01; // фон основного полотна/списка сообщений
const ALPHA_INPUT = 0.01; // фон поля ввода
const SCOPE_CLASS = 'kyan-chat-scope';
const IS_MOBILE = /Android|iPhone|iPad|Mobile/i.test(navigator.userAgent);
const SUPPORTS_BLUR = (typeof CSS!=='undefined') &&
(CSS.supports('backdrop-filter','blur(1px)') || CSS.supports('-webkit-backdrop-filter','blur(1px)'));
const EDGE_MOBILE = /\bEdgA\/|EdgiOS\//i.test(navigator.userAgent);
const USE_BLUR = SUPPORTS_BLUR && !EDGE_MOBILE;
const MENTION_BORDER = '3px solid rgba(34,142,93,0.85)';
function injectCSS(){
const old = document.getElementById('kyan-chat-style');
if (old) old.remove();
const css = `
.${SCOPE_CLASS} {}
/* ===== Прозрачность внутренних контейнеров (ШАПКУ НЕ СТЕКЛИМ) ===== */
.${SCOPE_CLASS} .chat2-widget-inner,
.${SCOPE_CLASS} .scrollable-content,
.${SCOPE_CLASS} [class*="chat2-body"],
.${SCOPE_CLASS} [class*="chat2-content"],
.${SCOPE_CLASS} [class*="chat2-container"],
.${SCOPE_CLASS} [class*="chat2-wrapper"],
.${SCOPE_CLASS} [class*="messages"],
.${SCOPE_CLASS} [class*="message-list"],
.${SCOPE_CLASS} [class*="list"],
.${SCOPE_CLASS} [class*="chat2-layout"],
.${SCOPE_CLASS} [class*="pane"],
.${SCOPE_CLASS} [class*="primary-darker"]:not(.chat2-header):not([class*="chat2-header"]),
.${SCOPE_CLASS} [class*="primary-dark"]:not(.chat2-header):not([class*="chat2-header"]) {
background: transparent !important;
background-color: transparent !important;
background-image: none !important;
}
/* Псевдоэлементы: обнуляем везде, кроме шапки */
.${SCOPE_CLASS} [class*="chat2-"]::before,
.${SCOPE_CLASS} [class*="chat2-"]::after { background: transparent !important; }
.${SCOPE_CLASS} .chat2-header *::before,
.${SCOPE_CLASS} .chat2-header *::after { background: initial !important; }
/* ===== Сообщения ===== */
.${SCOPE_CLASS} .chat2-message-block {
background: transparent !important;
border: 1px solid rgba(128,128,128,.45) !important;
border-radius: 6px !important;
}
.${SCOPE_CLASS} .reply-message {
background: transparent !important;
border: 1px solid rgba(128,128,128,.45) !important;
border-radius: 6px !important;
}
/* Панель «Ответ …» */
.${SCOPE_CLASS} .chat2-replying,
.${SCOPE_CLASS} [class*="replying"] {
background: rgba(0,0,0,.04) !important;
border: 1px solid rgba(128,128,128,.35) !important;
border-radius: 8px !important;
box-shadow: none !important;
}
.${SCOPE_CLASS} .chat2-replying-author { background: initial !important; }
.${SCOPE_CLASS} .chat2-replying * { border: none !important; box-shadow: none !important; }
/* Заголовки/ники внутри сообщения */
.${SCOPE_CLASS} .chat2-message-header,
.${SCOPE_CLASS} .chat2-message-header * {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
filter: none !important;
box-shadow: revert !important;
}
/* Поле ввода — почти прозрачное */
.${SCOPE_CLASS} .chat2-footer textarea,
.${SCOPE_CLASS} .chat2-footer [contenteditable="true"],
.${SCOPE_CLASS} .chat2-footer input[type="text"],
.${SCOPE_CLASS} .chat2-footer input[type="search"],
.${SCOPE_CLASS} .chat2-footer [class*="editor"] {
background: rgba(0,0,0,${ALPHA_INPUT}) !important;
border: none !important;
border-radius: 8px !important;
outline: none !important;
box-shadow: none !important;
}
/* Футер — не ломаем иконки/кнопки */
.${SCOPE_CLASS} .chat2-footer button,
.${SCOPE_CLASS} .chat2-footer [role="button"],
.${SCOPE_CLASS} .chat2-footer svg {
opacity: revert !important;
filter: none !important;
}
/* Кнопка отправки */
.${SCOPE_CLASS} .submit-btn { background: initial !important; }
/* Крестик «Отменить ответ» */
.${SCOPE_CLASS} .chat2-footer .chat2-cancel-reply {
display:inline-flex !important; align-items:center; justify-content:center;
width:22px; height:22px; border-radius:6px;
background: transparent !important; color:#fff !important;
opacity:1 !important; filter: drop-shadow(0 0 1px rgba(0,0,0,.7)) !important;
}
.${SCOPE_CLASS} .chat2-footer .chat2-cancel-reply:empty::before { content:'×'; font-size:16px; line-height:1; }
/* ===== Шапка чата ===== — только рамка, дочерние не трогаем */
.${SCOPE_CLASS} .chat2-header,
.${SCOPE_CLASS} .chat2-header.lztng-primary-dark,
.${SCOPE_CLASS} [class*="chat2-header"].lztng-primary-dark {
border: 1px solid rgba(128,128,128,.45) !important;
border-radius: 8px !important;
box-shadow: none !important;
overflow: visible !important;
background: initial !important;
backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
}
/* Упоминания — без заливки темы */
.${SCOPE_CLASS} .chat2-message.chat2-message-tagged,
.${SCOPE_CLASS} .chat2-message.chat2-message-tagged .chat2-message-block,
.${SCOPE_CLASS} .chat2-message.chat2-message-tagged .chat2-message-text,
.${SCOPE_CLASS} .chat2-message.chat2-message-tagged .chat2-message-header {
background: transparent !important; background-color: transparent !important; box-shadow: none !important;
}
.${SCOPE_CLASS} .reply-message.reply-message-your {
border: ${MENTION_BORDER} !important;
background: transparent !important;
}
/* Крестик «Редактирование сообщения» */
.${SCOPE_CLASS} .chat2-message-editing .chat2-cancel-editing {
display:inline-flex !important; align-items:center; justify-content:center;
width:22px; height:22px; border-radius:6px; background: transparent !important; color:#fff !important;
opacity:1 !important; filter: drop-shadow(0 0 1px rgba(0,0,0,.7)) !important; cursor: pointer !important;
}
.${SCOPE_CLASS} .chat2-message-editing .chat2-cancel-editing:empty::before { content:'×'; font-size:16px; line-height:1; }
/* Узел действий/кнопок в шапке — не обрезается */
.${SCOPE_CLASS} .chat2-header [class*="actions"],
.${SCOPE_CLASS} .chat2-header .chat2-title-actions {
position: relative !important;
z-index: 10020 !important;
pointer-events: auto !important;
overflow: visible !important;
}
/* ===== МОБАЙЛ: шапка скроллится + горизонтальная прокрутка ===== */
@media (max-width: 768px) {
.${SCOPE_CLASS} .chat2-header,
.${SCOPE_CLASS} [class*="chat2-header"] {
position: static !important;
top: auto !important; bottom: auto !important; transform: none !important; z-index: auto !important;
}
.${SCOPE_CLASS} .chat2-header,
.${SCOPE_CLASS} .chat2-header > * { overflow: visible !important; }
.${SCOPE_CLASS} .chat2-header [class*="actions"],
.${SCOPE_CLASS} .chat2-header .chat2-title-actions,
.${SCOPE_CLASS} .chat2-header .actions,
.${SCOPE_CLASS} .chat2-header .title-actions {
display: flex !important;
flex-wrap: nowrap !important;
align-items: center !important;
gap: .5rem !important;
width: 100% !important; max-width: 100% !important;
overflow-x: auto !important; overflow-y: hidden !important;
white-space: nowrap !important;
-webkit-overflow-scrolling: touch !important;
touch-action: pan-x !important;
overscroll-behavior-x: contain !important;
scroll-behavior: smooth !important;
scrollbar-width: thin;
}
.${SCOPE_CLASS} .chat2-header [class*="actions"] > *,
.${SCOPE_CLASS} .chat2-header .chat2-title-actions > * {
flex: 0 0 auto !important;
min-width: max-content !important;
}
}
`;
const tag = document.createElement('style');
tag.id = 'kyan-chat-style';
tag.textContent = css;
document.documentElement.appendChild(tag);
}
const qs = (r,s)=>r.querySelector(s);
const qsa = (r,s)=>Array.from(r.querySelectorAll(s));
function inlineGlass(el, alpha, blur, keepBorder=false){
if(!el) return;
el.style.setProperty('background', `rgba(0,0,0,${alpha})`, 'important');
el.style.setProperty('background-color', `rgba(0,0,0,${alpha})`, 'important');
el.style.setProperty('background-image', 'none', 'important');
if (USE_BLUR) {
el.style.setProperty('backdrop-filter', `blur(${blur}px)`, 'important');
el.style.setProperty('-webkit-backdrop-filter', `blur(${blur}px)`, 'important');
} else {
el.style.removeProperty('backdrop-filter');
el.style.removeProperty('-webkit-backdrop-filter');
}
if(!keepBorder) el.style.setProperty('border', 'none', 'important');
}
// На некоторых разметках нужные зоны отличаются — даём широкий охват
const GLASS_SELECTORS = [
// корневые
'#chat2-full',
'[class^="chat2-floating"]',
'.chat2',
'[class*="chat2-container"]',
'[class*="chatbox"]',
// основные области
'.scrollable-content',
'[class*="chat2-body"]',
'[class*="chat2-content"]',
'[class*="messages"]',
'[class*="message-list"]',
'.chat2-widget-inner',
// дополнительные обёртки, часто дают фон
'[class*="primary-darker"]:not(.chat2-header):not([class*="chat2-header"])',
'[class*="primary-dark"]:not(.chat2-header):not([class*="chat2-header"])',
'[class*="pane"]',
'[class*="layout"]',
'[class*="wrapper"]'
];
function applyGlassSet(root){
// Всегда — сам root
inlineGlass(root, ALPHA_GLASS, BLUR_PX, true);
// Все целевые селекторы
for (const sel of GLASS_SELECTORS){
qsa(root, sel).forEach(el => inlineGlass(el, ALPHA_GLASS, BLUR_PX, false));
}
// Поднимаемся вверх от ленты, чтобы пробить фон родителей
const scroll = findScroll(root);
if (scroll){
let p = scroll.parentElement, i=0;
while (p && p!==root && i<6){
inlineGlass(p, ALPHA_GLASS, BLUR_PX, true);
p = p.parentElement; i++;
}
}
}
function findChatRoot(){
return qs(document,'[class^="chat2-floating"]') ||
qs(document,'#chat2-full') ||
qs(document,'.chat2') ||
qs(document,'[class*="chat2-container"]') ||
qs(document,'[class*="chatbox"]');
}
function findScroll(root){
return qs(root,'.scrollable-content') ||
qs(root,'[class*="chat2-body"]') ||
qs(root,'[class*="chat2-content"]') ||
qs(root,'[class*="messages"]') ||
qs(root,'[class*="message-list"]');
}
function getMsgBlock(msg){
return msg.querySelector('.chat2-message-block') ||
msg.querySelector('.chat2-message-text') ||
msg.querySelector('div');
}
function setMentionBorderOnMessage(msg, on){
if (msg.classList.contains('reply-message') && msg.classList.contains('reply-message-your')){
if (on){
msg.style.setProperty('border', MENTION_BORDER, 'important');
msg.style.setProperty('background', 'transparent', 'important');
msg.style.setProperty('background-color', 'transparent', 'important');
} else {
msg.style.removeProperty('border');
msg.style.removeProperty('background');
msg.style.removeProperty('background-color');
}
return;
}
const block = getMsgBlock(msg);
if (!block) return;
if (on){
block.style.setProperty('border', MENTION_BORDER, 'important');
block.style.setProperty('background', 'transparent', 'important');
block.style.setProperty('background-color', 'transparent', 'important');
} else {
block.style.removeProperty('border');
block.style.removeProperty('background');
block.style.removeProperty('background-color');
}
}
function refreshMentions(root){
qsa(root, '.chat2-message, [class*="chat2-message"]').forEach(msg=>{
const tagged = msg.classList.contains('chat2-message-tagged');
setMentionBorderOnMessage(msg, tagged);
});
qsa(root, '.reply-message.reply-message-your').forEach(msg=>{
setMentionBorderOnMessage(msg, true);
});
}
// Наблюдение за DOM
let mo;
function watchAll(root, mode){
mo?.disconnect();
mo = new MutationObserver(()=>{
cancelAnimationFrame(watchAll._raf||0);
watchAll._raf = requestAnimationFrame(()=>{
applyGlassSet(root); // держим прозрачность после любых перерисовок
refreshMentions(root); // и зелёные рамки
});
});
mo.observe(root, { childList:true, subtree:true, attributes:true, attributeFilter:['class'] });
// первичное применение
applyGlassSet(root);
refreshMentions(root);
}
let moLayout;
function watchLayout(root, mode){
moLayout?.disconnect();
moLayout = new MutationObserver(()=>{
cancelAnimationFrame(watchLayout._raf||0);
watchLayout._raf = requestAnimationFrame(()=>{
applyGlassSet(root);
});
});
moLayout.observe(root, { childList:true, subtree:true });
}
function init(){
const root = findChatRoot();
if (!root){ setTimeout(init, 250); return; }
root.classList.add(SCOPE_CLASS);
injectCSS();
// НЕ стеклим шапку — только рамка через CSS (прозрачность даём остальным)
applyGlassSet(root);
watchAll(root);
const ON_CHATBOX = /\/chatbox\/?$/.test(location.pathname);
watchLayout(root, ON_CHATBOX ? 'chatbox' : 'floating');
}
if (document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', init, { once:true });
} else {
init();
}
})();