GGS Tools

Тулза для сообщений на GGSel

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         GGS Tools
// @namespace    http://tampermonkey.net/
// @version      2.7.4.2
// @description  Тулза для сообщений на GGSel
// @license MIT
// @author       XaviersDev
// @match        https://seller.ggsel.com/messages*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    
    const defaultData = {
        isFirstClickDone: false,
        templates: [
            { id: 1, title: 'Привет', text: 'Здравствуйте, (ник)! Чем могу помочь?' },
            { id: 2, title: 'Оставьте отзыв', text: 'Ваш товар готов, (ник). Спасибо за покупку,оставь отзыв!' }
        ],
        settings: {
            position: 'top',
            style: 'glass',
            size: 14,
            opacity: 0.7,
            textColor: '#00ffcc',
            bgColor: '#141414',
            autoSend: false 
        }
    };

    let appData = GM_getValue('ggs1_tools_data', defaultData);
    if (appData.settings.autoSend === undefined) appData.settings.autoSend = false;

    const saveData = () => GM_setValue('ggs1_tools_data', appData);

    let currentEditId = null; 

    
    function hexToRgba(hex, alpha) {
        let r = parseInt(hex.slice(1, 3), 16),
            g = parseInt(hex.slice(3, 5), 16),
            b = parseInt(hex.slice(5, 7), 16);
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }

    
    function setReactInputValue(inputElement, value) {
        const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
        nativeInputValueSetter.call(inputElement, value);
        inputElement.dispatchEvent(new Event('input', { bubbles: true }));
    }

    function getBuyerName() {
        try {
            const nameEl = document.querySelector('.styles_headerInfo__jj8f0 .styles_username__37KmO');
            if (nameEl) return nameEl.childNodes[0].textContent.trim();
        } catch (e) {}
        return "Покупатель";
    }

    
    const svgNoise = `url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.08'/%3E%3C/svg%3E")`;

    
    GM_addStyle(`
        /* Кнопка в хедере (Справа от колокольчика) */
        .ggs-header-btn {
            background: transparent; border: none; font-weight: 900; cursor: pointer;
            font-size: 18px; margin: 0 15px; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            letter-spacing: 0.5px; outline: none; z-index: 100; font-family: 'Unbounded', sans-serif;
        }
        .ggs-header-btn.fp-mode { color: #a200ff; text-shadow: 0 0 12px rgba(162,0,255,0.4); }
        .ggs-header-btn.fp-mode:hover { color: #d066ff; text-shadow: 0 0 20px rgba(208,102,255,0.9); transform: scale(1.05); }
        .ggs-header-btn.ggs-mode { color: #00ffcc; text-shadow: 0 0 12px rgba(0,255,204,0.4); }
        .ggs-header-btn.ggs-mode:hover { color: #00ffff; text-shadow: 0 0 20px rgba(0,255,255,0.9); transform: scale(1.05); }

        /* ЭПИЧНЫЕ АНИМАЦИИ */
        @keyframes ggsEpicShake {
            0% { transform: translate(2px, 2px) rotate(0deg) scale(1.2); }
            20% { transform: translate(-3px, -2px) rotate(-3deg) scale(1.3); }
            40% { transform: translate(3px, -4px) rotate(3deg) scale(1.4); }
            60% { transform: translate(-3px, 2px) rotate(-3deg) scale(1.5); }
            80% { transform: translate(2px, 3px) rotate(3deg) scale(1.4); }
            100% { transform: translate(-2px, -2px) rotate(0deg) scale(1.2); }
        }
        @keyframes ggsExplode {
            0% { transform: scale(1); filter: hue-rotate(0deg) brightness(1); }
            50% { transform: scale(1.6); filter: hue-rotate(180deg) brightness(2); text-shadow: 0 0 50px red; color: #ff0055;}
            100% { transform: scale(1); filter: hue-rotate(360deg) brightness(1); }
        }
        .ggs-anim-1 { animation: ggsEpicShake 0.1s infinite; color: #ff0055 !important; text-shadow: 0 0 20px #ff0055 !important; font-size: 20px !important; }
        .ggs-anim-2 { animation: ggsEpicShake 0.05s infinite, ggsExplode 0.4s infinite; color: #ff0000 !important; text-shadow: 0 0 40px #ff0000 !important; font-size: 26px !important; text-transform: uppercase; }

        /* ПЛАВАЮЩЕЕ МОДАЛЬНОЕ ОКНО */
        #ggs-modal-wrapper {
            position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
            z-index: 9999; display: none; opacity: 0; transition: opacity 0.3s ease;
        }
        #ggs-modal-wrapper.show { opacity: 1; display: block; }

        #ggs-modal {
            width: 850px; height: 580px; background: #141414; border: 1px solid #333;
            border-radius: 16px; display: flex; overflow: hidden; color: #eee;
            box-shadow: 0 25px 60px rgba(0,0,0,0.7); font-family: 'Inter', sans-serif;
            position: relative;
        }

        /* ЗОНА ПЕРЕТАСКИВАНИЯ (Драг-зона) */
        .ggs-drag-zone {
            position: absolute; top: 0; left: 0; width: 100%; height: 30px;
            cursor: move; z-index: 5; background: transparent;
        }
        /* Меняем курсор на краях */
        #ggs-modal::before {
            content: ''; position: absolute; inset: 0; border: 10px solid transparent;
            cursor: move; pointer-events: none; z-index: 100;
        }

        .ggs-close-btn {
            position: absolute; top: 15px; right: 15px; background: rgba(255,255,255,0.05);
            border: none; color: #888; width: 32px; height: 32px; border-radius: 8px;
            cursor: pointer; display: flex; align-items: center; justify-content: center;
            transition: 0.2s; z-index: 20;
        }
        .ggs-close-btn:hover { background: #ff4d4f; color: #fff; transform: rotate(90deg); }
        .ggs-close-btn svg { width: 16px; height: 16px; fill: currentColor; }

        .ggs-sidebar { width: 240px; background: #0f0f0f; border-right: 1px solid #2a2a2a; padding: 35px 0 20px; z-index: 10; position: relative; }
        .ggs-sidebar-header { padding: 0 25px 20px; font-size: 20px; font-weight: 900; color: #fff; letter-spacing: 0.5px; }
        .ggs-sidebar-btn {
            width: 100%; padding: 15px 25px; background: transparent; border: none;
            color: #888; text-align: left; font-size: 15px; font-weight: 500; cursor: pointer; transition: 0.2s;
        }
        .ggs-sidebar-btn:hover { color: #fff; background: rgba(255,255,255,0.02); }
        .ggs-sidebar-btn.active { color: #00ffcc; background: rgba(0,255,204,0.05); border-right: 3px solid #00ffcc; }

        .ggs-content { flex: 1; padding: 40px 30px 30px; overflow-y: auto; position: relative; z-index: 10; }
        .ggs-tab-content { display: none; animation: ggsFadeIn 0.3s ease; }
        .ggs-tab-content.active { display: block; }
        @keyframes ggsFadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }

        h2.ggs-title { margin: 0 0 5px 0; font-size: 24px; color: #fff; font-weight: 800; }
        p.ggs-subtitle { color: #888; font-size: 13px; margin: 0 0 20px 0; }

        .ggs-input, .ggs-textarea {
            width: 100%; background: #0a0a0a; border: 1px solid #333; color: #fff;
            padding: 12px 15px; border-radius: 8px; margin-bottom: 15px; outline: none;
            font-family: inherit; font-size: 14px; transition: 0.2s;
        }
        .ggs-input:focus, .ggs-textarea:focus { border-color: #00ffcc; box-shadow: 0 0 0 2px rgba(0,255,204,0.1); }
        .ggs-textarea { resize: vertical; min-height: 80px; }

        .ggs-btn {
            background: #00ffcc; color: #000; border: none; padding: 12px 20px;
            border-radius: 8px; cursor: pointer; font-weight: 700; font-size: 14px; transition: 0.2s;
        }
        .ggs-btn:hover { background: #00d2ff; transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,255,204,0.3); }
        .ggs-btn:active { transform: translateY(0); }
        .ggs-btn-danger { background: rgba(255,77,79,0.1); color: #ff4d4f; padding: 8px 12px; font-size: 12px;}
        .ggs-btn-danger:hover { background: #ff4d4f; color: #fff; }
        .ggs-btn-edit { background: rgba(255,204,0,0.1); color: #ffcc00; padding: 8px 12px; font-size: 12px; margin-right: 5px;}
        .ggs-btn-edit:hover { background: #ffcc00; color: #000; }

        .ggs-tpl-item {
            background: #111; border: 1px solid #2a2a2a; border-radius: 12px;
            padding: 15px 20px; margin-bottom: 12px; display: flex; justify-content: space-between;
            align-items: center; transition: 0.2s;
        }
        .ggs-tpl-item:hover { border-color: #444; }
        .ggs-tpl-info h4 { margin: 0 0 5px 0; color: #fff; font-size: 16px; font-weight: 600; }
        .ggs-tpl-info p { margin: 0; color: #777; font-size: 13px; max-width: 300px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

        /* Элементы настроек */
        .ggs-control-group { margin-bottom: 25px; }
        .ggs-control-label { display: block; font-size: 13px; font-weight: 600; color: #aaa; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 0.5px; }

        .ggs-radio-row { display: flex; gap: 10px; }
        .ggs-radio-btn {
            flex: 1; padding: 10px; text-align: center; background: #0a0a0a; border: 1px solid #333;
            border-radius: 8px; cursor: pointer; color: #888; font-size: 14px; font-weight: 500; transition: 0.2s;
        }
        .ggs-radio-btn:hover { background: #1a1a1a; border-color: #555; }
        .ggs-radio-btn.active { background: rgba(0,255,204,0.1); border-color: #00ffcc; color: #00ffcc; }

        .ggs-color-row { display: flex; gap: 15px; align-items: center; }
        .ggs-color-picker { -webkit-appearance: none; border: none; width: 40px; height: 40px; border-radius: 8px; cursor: pointer; background: none; padding: 0; }
        .ggs-color-picker::-webkit-color-swatch-wrapper { padding: 0; }
        .ggs-color-picker::-webkit-color-swatch { border: 1px solid #444; border-radius: 8px; }

        .ggs-slider-container { display: flex; align-items: center; gap: 15px; }
        .ggs-slider { flex: 1; -webkit-appearance: none; height: 6px; background: #333; border-radius: 3px; outline: none; }
        .ggs-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%; background: #00ffcc; cursor: pointer; transition: 0.2s; }
        .ggs-slider::-webkit-slider-thumb:hover { transform: scale(1.2); }
        .ggs-slider-val { width: 40px; text-align: right; color: #00ffcc; font-weight: 700; }

        /* Переключатель Авто-отправки */
        .ggs-switch-wrapper { display: flex; align-items: center; gap: 10px; cursor: pointer; margin-bottom: 20px; }
        .ggs-switch { position: relative; width: 40px; height: 20px; background: #333; border-radius: 10px; transition: 0.3s; }
        .ggs-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: #fff; border-radius: 50%; transition: 0.3s; }
        .ggs-switch.on { background: #00ffcc; }
        .ggs-switch.on::after { left: 22px; background: #000; }

        /* --- БИНДЫ В ЧАТЕ --- */
        .ggs-binds-container { display: flex; gap: 10px; flex-wrap: wrap; z-index: 10; margin: 0 0 10px 0; }
        .ggs-pos-top { margin-bottom: 12px; width: 100%; order: -1; }
        .ggs-pos-bottom { margin-top: 12px; width: 100%; order: 3; }
        .ggs-pos-left { flex-direction: column; margin-right: 12px; margin-bottom: 0; width: auto; order: -1; }
        .ggs-pos-right { flex-direction: column; margin-left: 12px; margin-bottom: 0; width: auto; order: 3; }
        .ggs-flex-row-hack { display: flex !important; flex-direction: row !important; align-items: flex-end; width: 100%; }

        .ggs-chat-bind {
            cursor: pointer; outline: none; white-space: nowrap; font-family: 'Inter', sans-serif;
            transition: all 0.25s cubic-bezier(0.2, 0.8, 0.2, 1); position: relative;
        }
        .ggs-chat-bind:hover { transform: translateY(-2px); filter: brightness(1.2); }
        .ggs-chat-bind:active { transform: translateY(1px) scale(0.98); filter: brightness(0.9); }

        /* TOOLTIP (Предпросмотр) */
        .ggs-chat-bind::after {
            content: attr(data-preview);
            position: absolute; bottom: 120%; left: 50%; transform: translateX(-50%) translateY(10px);
            background: rgba(10, 10, 10, 0.9); color: #fff;
            padding: 10px 14px; border-radius: 8px;
            font-size: 13px; font-weight: 300; letter-spacing: 0.3px; line-height: 1.4;
            white-space: pre-wrap; width: max-content; max-width: 320px; text-align: center;
            opacity: 0; pointer-events: none; transition: all 0.2s ease;
            box-shadow: 0 10px 25px rgba(0,0,0,0.8);
            border: 1px solid rgba(255,255,255,0.1);
            backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); z-index: 1000;
        }
        .ggs-chat-bind:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }
    `);

    
    function injectHeaderButton() {
        if (document.getElementById('ggs-main-btn')) return;

        const notifBtn = document.querySelector('a.styles_notification__w0Bwt');
        if (!notifBtn) return;

        const btn = document.createElement('button');
        btn.id = 'ggs-main-btn';
        btn.className = `ggs-header-btn ${appData.isFirstClickDone ? 'ggs-mode' : 'fp-mode'}`;
        btn.innerText = appData.isFirstClickDone ? 'GGS Tools' : 'FP Tools';

        btn.onclick = () => {
            if (!appData.isFirstClickDone) {
                
                btn.style.pointerEvents = 'none';
                btn.classList.add('ggs-anim-1');
                btn.innerText = "какой нахуй фп";

                setTimeout(() => {
                    btn.classList.replace('ggs-anim-1', 'ggs-anim-2');
                    btn.innerText = "ггсел тулс блять";

                    setTimeout(() => {
                        btn.classList.remove('ggs-anim-2');
                        btn.className = 'ggs-header-btn ggs-mode';
                        btn.innerText = "GGS Tools";
                        appData.isFirstClickDone = true;
                        saveData();

                        setTimeout(() => {
                            btn.style.pointerEvents = 'auto';
                            openModal();
                        }, 500);
                    }, 2000);
                }, 2000);
            } else {
                openModal();
            }
        };

        
        if (notifBtn.nextSibling) {
            notifBtn.parentNode.insertBefore(btn, notifBtn.nextSibling);
        } else {
            notifBtn.parentNode.appendChild(btn);
        }
    }

    
    function createModalUI() {
        if (document.getElementById('ggs-modal-wrapper')) return;

        const wrapper = document.createElement('div');
        wrapper.id = 'ggs-modal-wrapper';
        wrapper.innerHTML = `
            <div id="ggs-modal">
                <div class="ggs-drag-zone"></div>
                <button class="ggs-close-btn" id="ggs-close-btn">
                    <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
                </button>
                <div class="ggs-sidebar">
                    <div class="ggs-sidebar-header">GGS Tools</div>
                    <button class="ggs-sidebar-btn active" data-tab="tab-templates">📋 Шаблоны</button>
                    <button class="ggs-sidebar-btn" data-tab="tab-settings">🎨 Настройки вида</button>
                </div>
                <div class="ggs-content">

                    <!-- ВКЛАДКА: ШАБЛОНЫ -->
                    <div id="tab-templates" class="ggs-tab-content active">
                        <h2 class="ggs-title">Шаблоны быстрых ответов</h2>
                        <p class="ggs-subtitle">Используйте <b>(ник)</b> в тексте для автоматической подстановки.</p>

                        <div style="margin-bottom: 25px; background: rgba(255,255,255,0.02); padding: 20px; border-radius: 12px; border: 1px solid #2a2a2a;">
                            <input type="text" id="ggs-new-tpl-title" class="ggs-input" placeholder="Название кнопки (напр. Привет)">
                            <textarea id="ggs-new-tpl-text" class="ggs-textarea" placeholder="Здравствуйте, (ник)!"></textarea>
                            <div style="display:flex; gap:10px;">
                                <button class="ggs-btn" id="ggs-add-tpl-btn" style="flex:1;">+ Добавить шаблон</button>
                                <button class="ggs-btn ggs-btn-danger" id="ggs-cancel-edit-btn" style="display:none;">Отмена</button>
                            </div>
                        </div>
                        <div id="ggs-tpl-list"></div>
                    </div>

                    <!-- ВКЛАДКА: НАСТРОЙКИ ВИДА -->
                    <div id="tab-settings" class="ggs-tab-content">
                        <h2 class="ggs-title">ВНЕШНИЙ ВИД</h2>
                        <p class="ggs-subtitle">Изменения видны сразу</p>

                        <div class="ggs-switch-wrapper" id="ggs-autosend-toggle">
                            <div class="ggs-switch ${appData.settings.autoSend ? 'on' : ''}"></div>
                            <span style="color:#fff; font-weight:600;">Отправлять при нажатии</span>
                        </div>

                        <div class="ggs-control-group">
                            <span class="ggs-control-label">Расположение кнопок</span>
                            <div class="ggs-radio-row" id="group-pos">
                                <div class="ggs-radio-btn ${appData.settings.position === 'top' ? 'active' : ''}" data-val="top">Сверху</div>
                                <div class="ggs-radio-btn ${appData.settings.position === 'bottom' ? 'active' : ''}" data-val="bottom">Снизу</div>
                                <div class="ggs-radio-btn ${appData.settings.position === 'left' ? 'active' : ''}" data-val="left">Слева</div>
                                <div class="ggs-radio-btn ${appData.settings.position === 'right' ? 'active' : ''}" data-val="right">Справа</div>
                            </div>
                        </div>

                        <div class="ggs-control-group">
                            <span class="ggs-control-label">Стиль кнопок</span>
                            <div class="ggs-radio-row" id="group-style">
                                <div class="ggs-radio-btn ${appData.settings.style === 'solid' ? 'active' : ''}" data-val="solid">Заливка</div>
                                <div class="ggs-radio-btn ${appData.settings.style === 'outline' ? 'active' : ''}" data-val="outline">Обводка</div>
                                <div class="ggs-radio-btn ${appData.settings.style === 'glass' ? 'active' : ''}" data-val="glass">Стекло</div>
                            </div>
                        </div>

                        <div class="ggs-control-group">
                            <span class="ggs-control-label">Цвета</span>
                            <div class="ggs-color-row">
                                <input type="color" id="ggs-set-color" class="ggs-color-picker" value="${appData.settings.textColor}">
                                <span style="color:#aaa; font-size:13px; margin-right:15px;">Текст/Рамка</span>

                                <input type="color" id="ggs-set-bg" class="ggs-color-picker" value="${appData.settings.bgColor}">
                                <span style="color:#aaa; font-size:13px;">Фон</span>
                            </div>
                        </div>

                        <div class="ggs-control-group">
                            <span class="ggs-control-label">Прозрачность фона</span>
                            <div class="ggs-slider-container">
                                <input type="range" id="ggs-set-opacity" class="ggs-slider" min="0" max="1" step="0.05" value="${appData.settings.opacity}">
                                <span class="ggs-slider-val" id="val-opacity">${appData.settings.opacity}</span>
                            </div>
                        </div>

                        <div class="ggs-control-group">
                            <span class="ggs-control-label">Размер</span>
                            <div class="ggs-slider-container">
                                <input type="range" id="ggs-set-size" class="ggs-slider" min="10" max="24" step="1" value="${appData.settings.size}">
                                <span class="ggs-slider-val" id="val-size">${appData.settings.size}px</span>
                            </div>
                        </div>

                    </div>
                </div>
            </div>
        `;
        document.body.appendChild(wrapper);

        
        const modal = document.getElementById('ggs-modal');
        let isDragging = false, dragX = 0, dragY = 0;

        modal.addEventListener('mousedown', (e) => {
            
            if (e.target.closest('button, input, textarea, .ggs-radio-btn, .ggs-switch-wrapper')) return;
            isDragging = true;
            
            if (wrapper.style.transform !== 'none') {
                const rect = wrapper.getBoundingClientRect();
                wrapper.style.transform = 'none';
                wrapper.style.left = rect.left + 'px';
                wrapper.style.top = rect.top + 'px';
            }
            dragX = e.clientX - wrapper.offsetLeft;
            dragY = e.clientY - wrapper.offsetTop;
        });
        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            wrapper.style.left = (e.clientX - dragX) + 'px';
            wrapper.style.top = (e.clientY - dragY) + 'px';
        });
        document.addEventListener('mouseup', () => isDragging = false);

        
        document.getElementById('ggs-close-btn').onclick = () => {
            wrapper.classList.remove('show');
            setTimeout(() => wrapper.style.display='none', 300);
        };

        
        const shiftModal = (toCorner) => {
            wrapper.style.transform = 'none';
            if (toCorner) {
                wrapper.style.top = '30px';
                wrapper.style.left = 'calc(100vw - 880px)'; 
            } else {
                wrapper.style.top = '50%';
                wrapper.style.left = '50%';
                wrapper.style.transform = 'translate(-50%, -50%)';
            }
        };

        document.querySelectorAll('.ggs-sidebar-btn[data-tab]').forEach(btn => {
            btn.onclick = (e) => {
                document.querySelectorAll('.ggs-sidebar-btn').forEach(b => b.classList.remove('active'));
                document.querySelectorAll('.ggs-tab-content').forEach(c => c.classList.remove('active'));
                const targetBtn = e.target.closest('.ggs-sidebar-btn');
                targetBtn.classList.add('active');
                const tabId = targetBtn.dataset.tab;
                document.getElementById(tabId).classList.add('active');

                
                shiftModal(tabId === 'tab-settings');
            };
        });

        
        const titleInput = document.getElementById('ggs-new-tpl-title');
        const textInput = document.getElementById('ggs-new-tpl-text');
        const addBtn = document.getElementById('ggs-add-tpl-btn');
        const cancelBtn = document.getElementById('ggs-cancel-edit-btn');

        const resetForm = () => {
            titleInput.value = ''; textInput.value = '';
            currentEditId = null;
            addBtn.innerHTML = '+ Добавить шаблон';
            addBtn.style.background = '#00ffcc';
            cancelBtn.style.display = 'none';
        };

        addBtn.onclick = () => {
            const title = titleInput.value.trim();
            const text = textInput.value.trim();
            if(!title || !text) return;

            if (currentEditId) {
                
                const tpl = appData.templates.find(t => t.id === currentEditId);
                if(tpl) { tpl.title = title; tpl.text = text; }
            } else {
                
                appData.templates.push({ id: Date.now(), title, text });
            }

            saveData();
            resetForm();
            renderTemplatesList();
            renderChatBinds();
        };

        cancelBtn.onclick = resetForm;

        
        const updateSetting = (key, val) => {
            appData.settings[key] = val;
            saveData();
            renderChatBinds();
        };

        
        const autoSendToggle = document.getElementById('ggs-autosend-toggle');
        const switchEl = autoSendToggle.querySelector('.ggs-switch');
        autoSendToggle.onclick = () => {
            const newState = !appData.settings.autoSend;
            appData.settings.autoSend = newState;
            if(newState) switchEl.classList.add('on');
            else switchEl.classList.remove('on');
            saveData();
        };

        
        document.querySelectorAll('.ggs-radio-btn').forEach(btn => {
            btn.onclick = (e) => {
                const target = e.target;
                const parent = target.parentElement;
                parent.querySelectorAll('.ggs-radio-btn').forEach(b => b.classList.remove('active'));
                target.classList.add('active');
                if (parent.id === 'group-pos') updateSetting('position', target.dataset.val);
                if (parent.id === 'group-style') updateSetting('style', target.dataset.val);
            };
        });

        
        document.getElementById('ggs-set-color').oninput = (e) => updateSetting('textColor', e.target.value);
        document.getElementById('ggs-set-bg').oninput = (e) => updateSetting('bgColor', e.target.value);

        
        document.getElementById('ggs-set-opacity').oninput = (e) => {
            document.getElementById('val-opacity').innerText = e.target.value;
            updateSetting('opacity', e.target.value);
        };
        document.getElementById('ggs-set-size').oninput = (e) => {
            document.getElementById('val-size').innerText = e.target.value + 'px';
            updateSetting('size', e.target.value);
        };
    }

    function openModal() {
        createModalUI();
        renderTemplatesList();
        const wrapper = document.getElementById('ggs-modal-wrapper');
        wrapper.style.display = 'block';
        
        wrapper.style.top = '50%';
        wrapper.style.left = '50%';
        wrapper.style.transform = 'translate(-50%, -50%)';

        
        document.querySelector('.ggs-sidebar-btn[data-tab="tab-templates"]').click();

        setTimeout(() => wrapper.classList.add('show'), 10);
    }

    
    function renderTemplatesList() {
        const list = document.getElementById('ggs-tpl-list');
        if(!list) return;
        list.innerHTML = '';
        appData.templates.forEach(tpl => {
            const item = document.createElement('div');
            item.className = 'ggs-tpl-item';
            item.innerHTML = `
                <div class="ggs-tpl-info">
                    <h4>${tpl.title}</h4>
                    <p>${tpl.text}</p>
                </div>
                <div>
                    <button class="ggs-btn-edit" data-id="${tpl.id}">✏️</button>
                    <button class="ggs-btn-danger" data-id="${tpl.id}">🗑️</button>
                </div>
            `;
            list.appendChild(item);
        });

        
        document.querySelectorAll('.ggs-tpl-item .ggs-btn-danger').forEach(btn => {
            btn.onclick = (e) => {
                const id = parseInt(e.target.dataset.id);
                appData.templates = appData.templates.filter(t => t.id !== id);
                saveData();
                renderTemplatesList();
                renderChatBinds();
            };
        });

        
        document.querySelectorAll('.ggs-tpl-item .ggs-btn-edit').forEach(btn => {
            btn.onclick = (e) => {
                const id = parseInt(e.target.dataset.id);
                const tpl = appData.templates.find(t => t.id === id);
                if(!tpl) return;

                currentEditId = id;
                document.getElementById('ggs-new-tpl-title').value = tpl.title;
                document.getElementById('ggs-new-tpl-text').value = tpl.text;

                const addBtn = document.getElementById('ggs-add-tpl-btn');
                addBtn.innerHTML = '💾 Сохранить изменения';
                addBtn.style.background = '#ffcc00';
                document.getElementById('ggs-cancel-edit-btn').style.display = 'block';
            };
        });
    }

    
    function renderChatBinds() {
        const inputContainer = document.querySelector('.styles_inputContainer__nAC7C');
        const footerContainer = document.querySelector('.styles_footerContainer__E_RfM');

        if (!inputContainer || !footerContainer) return;

        const oldBinds = document.getElementById('ggs-binds-wrapper');
        if (oldBinds) oldBinds.remove();

        inputContainer.classList.remove('ggs-flex-row-hack');
        footerContainer.style.flexDirection = '';

        if (appData.templates.length === 0) return;

        const bindsWrapper = document.createElement('div');
        bindsWrapper.id = 'ggs-binds-wrapper';
        bindsWrapper.className = `ggs-binds-container ggs-pos-${appData.settings.position}`;

        const s = appData.settings;
        let btnCSS = `font-size: ${s.size}px; padding: 8px 14px; border-radius: 8px; font-weight: 600; `;

        
        if (s.style === 'solid') {
            const bg = hexToRgba(s.bgColor, s.opacity);
            btnCSS += `background-color: ${bg}; color: ${s.textColor}; border: 1px solid transparent;`;
        } else if (s.style === 'outline') {
            const bg = hexToRgba(s.bgColor, s.opacity * 0.2);
            btnCSS += `background-color: ${bg}; color: ${s.textColor}; border: 1px solid ${s.textColor};`;
        } else if (s.style === 'glass') {
            const bg = hexToRgba(s.bgColor, s.opacity);
            btnCSS += `
                background-color: ${bg};
                background-image: ${svgNoise};
                color: ${s.textColor};
                border: 1px solid rgba(255,255,255,0.15);
                backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px);
                box-shadow: 0 4px 10px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.1);
            `;
        }

        const buyerName = getBuyerName();

        appData.templates.forEach(tpl => {
            const btn = document.createElement('button');
            btn.className = 'ggs-chat-bind';
            btn.style.cssText = btnCSS;
            btn.innerText = tpl.title;

            
            const previewText = tpl.text.replace(/\(ник\)/gi, `@${buyerName}`).replace(/\{ник\}/gi, `@${buyerName}`);
            btn.setAttribute('data-preview', previewText);

            btn.onclick = () => {
                const textarea = inputContainer.querySelector('textarea');
                if (textarea) {
                    const finalMessage = tpl.text.replace(/\(ник\)/gi, buyerName).replace(/\{ник\}/gi, buyerName);

                    const currentVal = textarea.value;
                    const newVal = currentVal ? currentVal + ' ' + finalMessage : finalMessage;

                    setReactInputValue(textarea, newVal);
                    textarea.focus();

                    
                    if (appData.settings.autoSend) {
                        setTimeout(() => {
                            const enterEvent = new KeyboardEvent('keydown', {
                                bubbles: true, cancelable: true,
                                keyCode: 13, key: 'Enter', code: 'Enter'
                            });
                            textarea.dispatchEvent(enterEvent);
                        }, 50);
                    }
                }
            };
            bindsWrapper.appendChild(btn);
        });

        
        if (s.position === 'top' || s.position === 'bottom') {
            footerContainer.style.display = 'flex';
            footerContainer.style.flexDirection = 'column';
            if (s.position === 'top') {
                footerContainer.insertBefore(bindsWrapper, inputContainer);
            } else {
                footerContainer.appendChild(bindsWrapper);
            }
        } else if (s.position === 'left' || s.position === 'right') {
            inputContainer.classList.add('ggs-flex-row-hack');
            if (s.position === 'left') {
                inputContainer.insertBefore(bindsWrapper, inputContainer.firstChild);
            } else {
                inputContainer.appendChild(bindsWrapper);
            }
        }
    }

    
    const observer = new MutationObserver(() => {
        injectHeaderButton();
        const textarea = document.querySelector('.styles_inputContainer__nAC7C textarea');
        const bindsExist = document.getElementById('ggs-binds-wrapper');
        if (textarea && !bindsExist) {
            renderChatBinds();
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

})();