GGS Tools

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

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==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 });

})();