Torn.com Enhanced Chat Buttons V2

Add customizable buttons to Torn.com chat with enhanced UI and features

当前为 2025-04-09 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Torn.com Enhanced Chat Buttons V2
// @namespace    http://tampermonkey.net/
// @version      2.41
// @description  Add customizable buttons to Torn.com chat with enhanced UI and features
// @author       Created by Callz [2188704], updated by Weav3r [1853324]
// @match        https://www.torn.com/*
// @grant        GM_setClipboard
// ==/UserScript==

(function() {
    'use strict';

    const CACHE_TTL = 24 * 60 * 60 * 1000;

    const buttonCSS = `
        .custom-chat-button {
            background-color: #007BFF;
            color: white;
            padding: 2px 7px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 14px;
            margin: 4px 6px;
            cursor: pointer;
            border-radius: 5px;
            border: none;
            transition: transform 0.1s ease, box-shadow 0.1s ease;
            min-width: 80px;
            overflow: hidden;
            white-space: nowrap;
        }

        .custom-chat-button:active {
            transform: scale(0.95);
            box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
        }

        .custom-chat-button.recent {
            border: 2px solid #FFD700;
            box-shadow: 0 0 5px rgba(255, 215, 0, 0.8);
        }

        .custom-ui-panel {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #f5f5f5;
            padding: 10px;
            color: black;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
            z-index: 9999999999;
            width: 90%;
            max-width: 500px;
            box-sizing: border-box;
            max-height: 90vh;
            overflow: auto;
        }

        .custom-ui-panel h3 {
            font-size: 20px;
            margin-bottom: 10px;
            text-align: center;
        }

        .custom-ui-panel label {
            font-size: 14px;
            margin-bottom: 5px;
            display: block;
        }

        .custom-ui-panel input[type="text"],
        .custom-ui-panel select,
        .custom-ui-panel textarea {
            width: calc(100% - 12px);
            padding: 5px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 14px;
        }

        .custom-ui-panel input[type="color"] {
            padding: 0;
            margin-top: 5px;
            border: none;
        }

        .custom-ui-panel button {
            background-color: #007BFF;
            color: white;
            border: none;
            padding: 8px 12px;
            border-radius: 5px;
            cursor: pointer;
            margin: 5px;
            font-size: 14px;
            transition: background-color 0.3s ease;
        }

        .custom-ui-panel button#close-ui {
            background-color: #ccc;
        }

        .custom-ui-panel button#close-ui:hover {
            background-color: #999;
        }

        .custom-ui-panel textarea {
            height: 60px;
            resize: vertical;
            position: relative;
        }

        .custom-ui-panel hr {
            margin: 10px 0;
            border: 0;
            border-top: 1px solid #ccc;
        }

        .char-counter {
            position: absolute;
            bottom: 10px;
            right: 10px;
            font-size: 12px;
            color: #999;
        }

        #chat-config-button {
           color: green;
       }

        #button-configs {
            max-height: 400px;
            overflow-y: auto;
            margin-bottom: 10px;
        }

        @media (max-width: 600px) {
            .custom-ui-panel {
                width: 95%;
                max-width: none;
                padding: 8px;
            }

            .custom-ui-panel h3 {
                font-size: 18px;
            }

            .custom-ui-panel label,
            .custom-ui-panel button {
                font-size: 12px;
            }

            .custom-ui-panel input[type="text"],
            .custom-ui-panel select,
            .custom-ui-panel textarea {
                font-size: 12px;
            }

            .custom-ui-panel button {
                padding: 6px 10px;
            }

            .char-counter {
                font-size: 10px;
            }
        }

        .tabs {
            display: flex;
            margin-bottom: 10px;
        }

        .tab {
            flex: 1;
            padding: 10px;
            cursor: pointer;
            text-align: center;
            background-color: #e9e9e9;
            border: 1px solid #ccc;
            border-bottom: none;
            border-radius: 10px 10px 0 0;
        }

        .tab.settings-tab {
            flex: 0.2;
            padding: 10px;
            cursor: pointer;
            text-align: center;
            background-color: #e9e9e9;
            border: 1px solid #ccc;
            border-bottom: none;
            border-radius: 10px 10px 0 0;
        }

        .tab.active {
            background-color: #fff;
            border-bottom: 1px solid #fff;
        }

        .tab-content {
            display: none;
        }

        .tab-content.active {
            display: block;
        }

        .custom-ui-panel.config-list-tab-active {
            max-height: 80vh;
        }

        .search-container {
            display: flex;
            margin-bottom: 10px;
        }

        .search-container input[type="text"] {
            flex: 3;
            padding: 5px;
            margin-right: 5px;
        }

        .search-container select {
            flex: 1;
            padding: 5px;
        }

        .highlight {
            background-color: yellow;
        }

        .tt-chat-filter {
            display: flex;
            padding: 4px;
            align-items: center;
            background-color: var(--chat-box-bg);
            color: var(--chat-box-label-info);
            border-bottom: 1px solid var(--chat-box-input-border);
            margin-bottom: 8px;
        }

        .tt-chat-filter input {
            margin-left: 4px;
            margin-right: 4px;
            border-radius: 5px;
            width: -webkit-fill-available;
            width: -moz-available;
            border: 1px solid var(--chat-box-input-border);
            background-color: var(--chat-box-bg);
            color: var(--chat-box-label-info);
        }

        .notification {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 10px;
            border-radius: 5px;
            z-index: 9999999999;
            opacity: 0;
            transition: opacity 0.5s ease;
        }

        .notification.show {
            opacity: 1;
        }

        .button-config-card {
            border: 1px solid #ccc;
            background-color: #fff;
            padding: 10px;
            margin: 10px 0;
            border-radius: 5px;
        }

        .button-config-message {
            white-space: pre-wrap;
            background: #f9f9f9;
            padding: 5px;
            border-radius: 5px;
            border: 1px solid #ddd;
            margin: 5px 0;
        }
    `;

    const conditions = {
        TradeChat: chatBox => {
            // New chat version
            if (chatBox.id === 'public_trade') return true;
            // Old chat version
            const oldTitle = chatBox.querySelector('.chat-box-header__name___jIjjM');
            return oldTitle && oldTitle.textContent === 'Trade';
        },
        HospitalChat: chatBox => {
            // New chat version
            if (chatBox.id === 'public_hospital') return true;
            // Old chat version
            const oldTitle = chatBox.querySelector('.chat-box-header__name___jIjjM');
            return oldTitle && oldTitle.textContent === 'Hospital';
        },
        FactionChat: chatBox => {
            // New chat version
            if (chatBox.id && chatBox.id.startsWith('faction-')) return true;
            // Old chat version
            const oldTitle = chatBox.querySelector('.chat-box-header__name___jIjjM');
            return oldTitle && oldTitle.textContent === 'Faction';
        },
        CompanyChat: chatBox => {
            // New chat version
            if (chatBox.id && chatBox.id.startsWith('company-')) return true;
            // Old chat version
            const oldTitle = chatBox.querySelector('.chat-box-header__name___jIjjM');
            return oldTitle && oldTitle.textContent === 'Company';
        },
        GlobalChat: chatBox => {
            // New chat version
            if (chatBox.id === 'public_global') return true;
            // Old chat version
            const oldTitle = chatBox.querySelector('.chat-box-header__name___jIjjM');
            return oldTitle && oldTitle.textContent === 'Global';
        },
        UserChat: chatBox => {
            // New chat version
            if (chatBox.id && chatBox.id.startsWith('private-')) return true;
            // Old chat version
            return chatBox.querySelector('.chat-box-header__options___nTsMU') !== null;
        }
    };

    const companyTypes = {
        1: "Hair Salon",
        2: "Law Firm",
        3: "Flower Shop",
        4: "Car Dealership",
        5: "Clothing Store",
        6: "Gun Shop",
        7: "Game Shop",
        8: "Candle Shop",
        9: "Toy Shop",
        10: "Adult Novelties",
        11: "Cyber Cafe",
        12: "Grocery Store",
        13: "Theater",
        14: "Sweet Shop",
        15: "Cruise Line",
        16: "Television Network",
        18: "Zoo",
        19: "Firework Stand",
        20: "Property Broker",
        21: "Furniture Store",
        22: "Gas Station",
        23: "Music Store",
        24: "Nightclub",
        25: "Pub",
        26: "Gents Strip Club",
        27: "Restaurant",
        28: "Oil Rig",
        29: "Fitness Center",
        30: "Mechanic Shop",
        31: "Amusement Park",
        32: "Lingerie Store",
        33: "Meat Warehouse",
        34: "Farm",
        35: "Software Corporation",
        36: "Ladies Strip Club",
        37: "Private Security Firm",
        38: "Mining Corporation",
        39: "Detective Agency",
        40: "Logistics Management",
    };

    function addCSS(cssString) {
        const style = document.createElement('style');
        style.textContent = cssString;
        document.head.append(style);
    }

    function showNotification(message) {
        const notification = document.createElement('div');
        notification.className = 'notification';
        notification.innerText = message;
        document.body.appendChild(notification);
        requestAnimationFrame(() => {
            notification.classList.add('show');
        });
        setTimeout(() => {
            notification.classList.remove('show');
            setTimeout(() => {
                notification.remove();
            }, 500);
        }, 2000);
    }

    function saveRecentButtonInfo(buttonText, chatBoxName) {
        localStorage.setItem('recentButtonInfo', JSON.stringify({ buttonText, chatBoxName }));
    }

    function clearRecentButtonInfo() {
        localStorage.removeItem('recentButtonInfo');
    }

    function getButtonConfigurations() {
        return JSON.parse(localStorage.getItem('chatButtonConfig')) || { buttons: [] };
    }

    function saveButtonConfigurations(config) {
        localStorage.setItem('chatButtonConfig', JSON.stringify(config));
    }

    function getAPIKey() {
        return localStorage.getItem('apiKey') || '';
    }

    function saveAPIKey(key) {
        localStorage.setItem('apiKey', key);
        showNotification('API key saved.');
    }

    function saveCache(key, data) {
        const cacheData = {
            timestamp: Date.now(),
            data
        };
        localStorage.setItem(key, JSON.stringify(cacheData));
    }

    function loadCache(key) {
        const cacheData = JSON.parse(localStorage.getItem(key));
        if (cacheData && (Date.now() - cacheData.timestamp < CACHE_TTL)) {
            return cacheData.data;
        }
        return null;
    }

    function clearCache() {
        localStorage.removeItem('companyCache');
        localStorage.removeItem('factionCache');
        showNotification('API cache cleared.');
    }

    function createUIPanel() {
        if (document.querySelector('.custom-ui-panel')) {
            return;
        }

        const panel = document.createElement('div');
        panel.className = 'custom-ui-panel';
        panel.innerHTML = `
            <div class="tabs">
                <div class="tab active" data-tab="config-list-tab">Configured Buttons</div>
                <div class="tab" data-tab="config-edit-tab">Create/Edit Button</div>
                <div class="tab settings-tab" data-tab="config-settings-tab">⚙️</div>
            </div>
            <div id="config-list-tab" class="tab-content active">
                <div class="search-container">
                    <input type="text" id="search-input" placeholder="Search...">
                    <select id="search-select">
                        <option value="buttonText">Text</option>
                        <option value="condition">Condition</option>
                        <option value="text">Message</option>
                    </select>
                </div>
                <div id="button-configs"></div>
            </div>
            <div id="config-edit-tab" class="tab-content">
                <div>
                    <label for="button-text">Button Text</label>
                    <input type="text" id="button-text" placeholder="Button Text">

                    <label for="button-color">Background Color</label>
                    <input type="color" id="button-color">

                    <label for="button-condition">Condition</label>
                    <select id="button-condition">
                        <option value="TradeChat">Trade Chat</option>
                        <option value="HospitalChat">Hospital Chat</option>
                        <option value="FactionChat">Faction Chat</option>
                        <option value="CompanyChat">Company Chat</option>
                        <option value="GlobalChat">Global Chat</option>
                        <option value="UserChat">User Chat</option>
                    </select>

                    <label for="button-text-content">Message</label>
                    <textarea id="button-text-content" placeholder="Enter your message here. Use {name} for chatter's name, {company} for company info, {faction} for faction info."></textarea>
                    <div class="char-counter" id="char-counter">0</div>

                    <button id="add-button">Add Button</button>
                    <button id="edit-button" style="display: none;">Save Button</button>
                </div>
            </div>
            <div id="config-settings-tab" class="tab-content">
                <label for="api-key">API Key</label>
                <input type="text" id="api-key" placeholder="Enter your API key" value="${getAPIKey()}">
                <button id="save-api-key-button">Save API Key</button>
                <button id="import-button">Import Config (File)</button>
                <button id="export-button">Export Config (File)</button>
                <button id="clear-cache-button">Clear API Cache</button>
            </div>
            <button id="close-ui">Close</button>
        `;
        document.body.appendChild(panel);

        document.querySelectorAll('.tab').forEach(tab => {
            tab.addEventListener('click', () => {
                switchTab(tab.dataset.tab);
            });
        });

        document.getElementById('add-button').addEventListener('click', addNewButtonConfig);
        document.getElementById('edit-button').addEventListener('click', editButtonConfig);
        document.getElementById('close-ui').addEventListener('click', closeUI);
        document.getElementById('import-button').addEventListener('click', importConfig);
        document.getElementById('export-button').addEventListener('click', exportConfig);
        document.getElementById('clear-cache-button').addEventListener('click', clearCache);
        document.getElementById('button-text-content').addEventListener('input', updateCharCounter);
        document.getElementById('search-input').addEventListener('input', filterButtonConfigs);
        document.getElementById('save-api-key-button').addEventListener('click', () => {
            const key = document.getElementById('api-key').value;
            saveAPIKey(key);
        });

        populateButtonConfigs();
    }

    function switchTab(tabId) {
        document.querySelectorAll('.tab, .tab-content').forEach(el => {
            el.classList.remove('active');
        });
        document.querySelector(`[data-tab="${tabId}"]`).classList.add('active');
        document.getElementById(tabId).classList.add('active');

        const panel = document.querySelector('.custom-ui-panel');
        if (tabId === 'config-list-tab') {
            panel.classList.add('config-list-tab-active');
        } else {
            panel.classList.remove('config-list-tab-active');
        }
    }

    function populateButtonConfigs() {
        const configsContainer = document.getElementById('button-configs');
        configsContainer.innerHTML = '';
        const configs = getButtonConfigurations();

        configs.buttons.forEach((buttonConfig, index) => {
            const configDiv = document.createElement('div');
            configDiv.className = 'button-config-card draggable';
            configDiv.dataset.index = index;

            const textDiv = document.createElement('div');
            textDiv.innerHTML = `<strong>Text:</strong> ${buttonConfig.buttonText}`;
            configDiv.appendChild(textDiv);

            const colorDiv = document.createElement('div');
            colorDiv.innerHTML = `<strong>Color:</strong> ${buttonConfig.backgroundColor}`;
            configDiv.appendChild(colorDiv);

            const conditionDiv = document.createElement('div');
            conditionDiv.innerHTML = `<strong>Condition:</strong> ${buttonConfig.condition}`;
            configDiv.appendChild(conditionDiv);

            const messageDiv = document.createElement('div');
            messageDiv.className = 'button-config-message';
            messageDiv.innerText = buttonConfig.text;
            configDiv.appendChild(messageDiv);

            const editButton = document.createElement('button');
            editButton.textContent = 'Edit';
            editButton.addEventListener('click', () => {
                selectForEdit(index);
                switchTab('config-edit-tab');
            });
            configDiv.appendChild(editButton);

            const deleteButton = document.createElement('button');
            deleteButton.textContent = 'Delete';
            deleteButton.addEventListener('click', () => deleteButtonConfig(index));
            configDiv.appendChild(deleteButton);

            const moveUpButton = document.createElement('button');
            moveUpButton.textContent = 'Up';
            moveUpButton.addEventListener('click', () => moveButtonConfig(index, -1));
            configDiv.appendChild(moveUpButton);

            const moveDownButton = document.createElement('button');
            moveDownButton.textContent = 'Down';
            moveDownButton.addEventListener('click', () => moveButtonConfig(index, 1));
            configDiv.appendChild(moveDownButton);

            configsContainer.appendChild(configDiv);
        });
    }

    function filterButtonConfigs() {
        const searchInput = document.getElementById('search-input').value.toLowerCase();
        const searchBy = document.getElementById('search-select').value;
        const configs = getButtonConfigurations();

        const filteredConfigs = configs.buttons.filter(buttonConfig => {
            const fieldValue = buttonConfig[searchBy].toLowerCase();
            return fieldValue.includes(searchInput);
        });

        const configsContainer = document.getElementById('button-configs');
        configsContainer.innerHTML = '';

        filteredConfigs.forEach((buttonConfig, index) => {
            const configDiv = document.createElement('div');
            configDiv.className = 'button-config-card draggable';
            configDiv.dataset.index = index;

            const textDiv = document.createElement('div');
            textDiv.innerHTML = `<strong>Text:</strong> ${buttonConfig.buttonText}`;
            configDiv.appendChild(textDiv);

            const colorDiv = document.createElement('div');
            colorDiv.innerHTML = `<strong>Color:</strong> ${buttonConfig.backgroundColor}`;
            configDiv.appendChild(colorDiv);

            const conditionDiv = document.createElement('div');
            conditionDiv.innerHTML = `<strong>Condition:</strong> ${buttonConfig.condition}`;
            configDiv.appendChild(conditionDiv);

            const messageDiv = document.createElement('div');
            messageDiv.className = 'button-config-message';
            messageDiv.innerText = buttonConfig.text;
            configDiv.appendChild(messageDiv);

            const editButton = document.createElement('button');
            editButton.textContent = 'Edit';
            editButton.addEventListener('click', () => {
                selectForEdit(index);
                switchTab('config-edit-tab');
            });
            configDiv.appendChild(editButton);

            const deleteButton = document.createElement('button');
            deleteButton.textContent = 'Delete';
            deleteButton.addEventListener('click', () => deleteButtonConfig(index));
            configDiv.appendChild(deleteButton);

            const moveUpButton = document.createElement('button');
            moveUpButton.textContent = 'Up';
            moveUpButton.addEventListener('click', () => moveButtonConfig(index, -1));
            configDiv.appendChild(moveUpButton);

            const moveDownButton = document.createElement('button');
            moveDownButton.textContent = 'Down';
            moveDownButton.addEventListener('click', () => moveButtonConfig(index, 1));
            configDiv.appendChild(moveDownButton);

            configsContainer.appendChild(configDiv);
        });
    }

    function selectForEdit(index) {
        const config = getButtonConfigurations().buttons[index];
        document.getElementById('button-text').value = config.buttonText;
        document.getElementById('button-color').value = config.backgroundColor;
        document.getElementById('button-condition').value = config.condition;
        document.getElementById('button-text-content').value = config.text;

        document.getElementById('add-button').style.display = 'block';
        document.getElementById('edit-button').style.display = 'block';
        document.getElementById('edit-button').setAttribute('data-edit-index', index);
        updateCharCounter();
    }

    function deleteButtonConfig(index) {
        const config = getButtonConfigurations();
        config.buttons.splice(index, 1);
        saveButtonConfigurations(config);
        populateButtonConfigs();
        showNotification('Button deleted.');
    }

    function moveButtonConfig(index, direction) {
        const config = getButtonConfigurations();
        const newIndex = index + direction;

        if (newIndex >= 0 && newIndex < config.buttons.length) {
            const buttonConfig = config.buttons.splice(index, 1)[0];
            config.buttons.splice(newIndex, 0, buttonConfig);
            saveButtonConfigurations(config);
            populateButtonConfigs();
            showNotification('Button moved.');
        }
    }

    function addNewButtonConfig() {
        const buttonText = document.getElementById('button-text').value;
        const backgroundColor = document.getElementById('button-color').value;
        const condition = document.getElementById('button-condition').value;
        const text = document.getElementById('button-text-content').value;

        const config = getButtonConfigurations();
        config.buttons.push({ buttonText, backgroundColor, condition, text });
        saveButtonConfigurations(config);
        populateButtonConfigs();
        highlightButton(config.buttons.length - 1);
        switchTab('config-list-tab');

        clearInputFields();
        showNotification('Button added.');
    }

    function editButtonConfig() {
        const index = parseInt(document.getElementById('edit-button').getAttribute('data-edit-index'), 10);
        const buttonText = document.getElementById('button-text').value;
        const backgroundColor = document.getElementById('button-color').value;
        const condition = document.getElementById('button-condition').value;
        const text = document.getElementById('button-text-content').value;

        const config = getButtonConfigurations();
        config.buttons[index] = { buttonText, backgroundColor, condition, text };
        saveButtonConfigurations(config);
        populateButtonConfigs();
        highlightButton(index);
        switchTab('config-list-tab');

        document.getElementById('add-button').style.display = 'block';
        document.getElementById('edit-button').style.display = 'none';

        clearInputFields();
        showNotification('Button edited.');
    }

    function clearInputFields() {
        document.getElementById('button-text').value = '';
        document.getElementById('button-text-content').value = '';
        document.getElementById('button-color').value = '';
        updateCharCounter();
    }

    function closeUI() {
        const panel = document.querySelector('.custom-ui-panel');
        if (panel) {
            panel.remove();
        }
    }

    function createConfigButton() {
        const peopleButton = document.querySelector('#people_panel_button');
        if (!peopleButton || document.querySelector('#chat-config-button')) return;

        const button = document.createElement('button');
        button.id = 'chat-config-button';
        button.type = 'button';
        button.title = 'Edit Chat Buttons';
        button.className = 'root___WHFbh root___J_YsG';

        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
        svg.setAttribute('viewBox', '0 0 512 512');
        svg.setAttribute('height', '24');
        svg.setAttribute('width', '24');
        svg.classList.add('root___DYylw', 'icon___M_Izz');
        svg.innerHTML = `
            <path d="M312 201.8c0-17.4 9.2-33.2 19.9-47C344.5 138.5 352 118.1 352 96c0-53-43-96-96-96s-96 43-96 96c0 22.1 7.5 42.5 20.1 58.8c10.7 13.8 19.9 29.6 19.9 47c0 29.9-24.3 54.2-54.2 54.2L112 256C50.1 256 0 306.1 0 368c0 20.9 13.4 38.7 32 45.3L32 464c0 26.5 21.5 48 48 48l352 0c26.5 0 48-21.5 48-48l0-50.7c18.6-6.6 32-24.4 32-45.3c0-61.9-50.1-112-112-112l-33.8 0c-29.9 0-54.2-24.3-54.2-54.2zM416 416l0 32L96 448l0-32 320 0z" fill="url(#config-default-blue)"/>
            <defs>
                <linearGradient id="config-default-blue" x1="0.5" x2="0.5" y2="1">
                    <stop offset="0" stop-color="#8faeb4"/>
                    <stop offset="1" stop-color="#638c94"/>
                </linearGradient>
                <linearGradient id="config-hover-blue" x1="0.5" x2="0.5" y2="1">
                    <stop offset="0" stop-color="#eaf0f1"/>
                    <stop offset="1" stop-color="#7b9fa6"/>
                </linearGradient>
            </defs>
        `;

        button.appendChild(svg);
        button.addEventListener('click', createUIPanel);

        const path = svg.querySelector('path');
        button.addEventListener('mouseenter', () => path.setAttribute('fill', 'url(#config-hover-blue)'));
        button.addEventListener('mouseleave', () => path.setAttribute('fill', 'url(#config-default-blue)'));

        peopleButton.insertAdjacentElement('afterend', button);
    }

    function applyButtonConfigurations() {
        const configs = getButtonConfigurations();
        // Query for both old and new chat window classes
        document.querySelectorAll('.root___FmdS_, .chat-box___mHm01').forEach(chatBox => {
            configs.buttons.forEach(buttonConfig => {
                const conditionFunc = conditions[buttonConfig.condition];
                if (conditionFunc && conditionFunc(chatBox) && !chatBox.querySelector(`[data-button-text="${buttonConfig.buttonText}"]`)) {
                    const button = document.createElement('button');
                    button.className = 'custom-chat-button';
                    button.innerText = buttonConfig.buttonText;
                    button.style.backgroundColor = buttonConfig.backgroundColor;
                    button.setAttribute('data-button-text', buttonConfig.buttonText);
                    button.addEventListener('click', (event) => addCustomText(chatBox, buttonConfig.text, event));
                    button.addEventListener('mousedown', (event) => {
                        if (event.button === 0) {
                            let timer;
                            const delay = 1000;
                            timer = setTimeout(() => {
                                button.classList.remove('recent');
                                clearRecentButtonInfo();
                            }, delay);
                            button.addEventListener('mouseup', () => {
                                clearTimeout(timer);
                            }, { once: true });
                            button.addEventListener('mouseleave', () => {
                                clearTimeout(timer);
                            }, { once: true });
                        }
                    });

                    // Try both new and old input container selectors
                    const inputContainer = chatBox.querySelector('.root___WUd1h') || chatBox.querySelector('.chat-box-footer___YK914');
                    if (inputContainer) {
                        let buttonContainer = chatBox.querySelector('.button-container');
                        if (!buttonContainer) {
                            buttonContainer = document.createElement('div');
                            buttonContainer.className = 'button-container';
                            buttonContainer.style.display = 'flex';
                            buttonContainer.style.flexWrap = 'wrap';
                            inputContainer.insertAdjacentElement('beforebegin', buttonContainer);
                        }
                        buttonContainer.appendChild(button);
                    }
                }
            });
        });
    }

    async function addCustomText(chatBox, messageTemplate, event) {
        let name = 'User';
        // Try both new and old name selectors
        const titleElement = chatBox.querySelector('.title___Bmq5P') || 
                           chatBox.querySelector('.typography___Dc5WV') ||
                           chatBox.querySelector('.chat-box-header__name___jIjjM');
        if (titleElement) {
            name = titleElement.textContent.trim();
        }
        let message = messageTemplate.replace('{name}', name);

        if (message.includes('{company}')) {
            const apiKey = getAPIKey();
            if (!apiKey) {
                alert('API key not set. Please set the API key in the settings tab.');
                return;
            }

            let companyInfo = loadCache('companyCache');
            if (!companyInfo) {
                const apiUrl = `https://api.torn.com/company/?selections=profile&key=${apiKey}`;
                try {
                    const response = await fetch(apiUrl);
                    const data = await response.json();
                    if (!data.error && data.company) {
                        companyInfo = data.company;
                        saveCache('companyCache', companyInfo);
                    } else {
                        alert('Failed to retrieve company information. Check your API key.');
                        return;
                    }
                } catch (error) {
                    alert('Error fetching company information:', error);
                    return;
                }
            }

            const companyType = companyTypes[companyInfo.company_type] || 'Unknown';
            const companyDetails = `${companyInfo.rating}* ${companyType}`;
            message = message.replace('{company}', companyDetails);
        }

        if (message.includes('{faction}')) {
            const apiKey = getAPIKey();
            if (!apiKey) {
                alert('API key not set. Please set the API key in the settings tab.');
                return;
            }

            let factionInfo = loadCache('factionCache');
            if (!factionInfo) {
                const apiUrl = `https://api.torn.com/faction/?selections=basic&key=${apiKey}`;
                try {
                    const response = await fetch(apiUrl);
                    const data = await response.json();
                    if (!data.error && data.respect && data.name && data.rank) {
                        factionInfo = data;
                        saveCache('factionCache', factionInfo);
                    } else {
                        alert('Failed to retrieve faction information. Check your API key.');
                        return;
                    }
                } catch (error) {
                    alert('Error fetching faction information:', error);
                    return;
                }
            }

            const respectFormatted = factionInfo.respect >= 1000000 ? (factionInfo.respect / 1000000).toFixed(1) + 'm' : (factionInfo.respect / 1000).toFixed(1) + 'k';
            const factionDetails = `${factionInfo.name}, ${factionInfo.rank.name} Ranked ${respectFormatted} Respect`;
            message = message.replace('{faction}', factionDetails);
        }

        insertMessage(chatBox, message, event.target);
    }

    function insertMessage(chatBox, message, targetButton) {
        navigator.clipboard.writeText(message).then(() => {
            // Try both new and old textarea selectors
            const textArea = chatBox.querySelector('.textarea___V8HsV') || chatBox.querySelector('textarea');
            if (!textArea) return;
            textArea.focus();
            const startPos = textArea.selectionStart;
            const endPos = textArea.selectionEnd;
            textArea.setRangeText(message, startPos, endPos, 'end');
            textArea.dispatchEvent(new Event('input', { bubbles: true }));
            textArea.focus();
            textArea.selectionStart = textArea.selectionEnd = startPos + message.length;

            document.querySelectorAll('.custom-chat-button').forEach(btn => {
                btn.classList.remove('recent');
            });
            targetButton.classList.add('recent');

            // Try both new and old title selectors
            const titleElement = chatBox.querySelector('.title___Bmq5P') || 
                               chatBox.querySelector('.chat-box-header__name___jIjjM');
            const chatBoxName = titleElement ? titleElement.textContent.trim() : '';
            saveRecentButtonInfo(targetButton.getAttribute('data-button-text'), chatBoxName);
        });
    }

    function applyRecentButtonClass() {
        const recentButtonInfo = JSON.parse(localStorage.getItem('recentButtonInfo'));
        if (recentButtonInfo) {
            document.querySelectorAll('.custom-chat-button').forEach(btn => {
                btn.classList.remove('recent');
            });

            // Query for both old and new chat window classes
            document.querySelectorAll('.root___FmdS_, .chat-box___mHm01').forEach(chatBox => {
                // Try both new and old title selectors
                const titleElement = chatBox.querySelector('.title___Bmq5P') || 
                                   chatBox.querySelector('.chat-box-header__name___jIjjM');
                const chatBoxName = titleElement ? titleElement.textContent.trim() : '';
                if (chatBoxName === recentButtonInfo.chatBoxName) {
                    const button = chatBox.querySelector(`[data-button-text="${recentButtonInfo.buttonText}"]`);
                    if (button) {
                        button.classList.add('recent');
                    }
                }
            });
        }
    }

    function importConfig() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';
        input.onchange = async (event) => {
            const file = event.target.files[0];
            if (!file) {
                showNotification('No file selected.');
                return;
            }
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const config = JSON.parse(e.target.result);
                    if (config && config.buttons) {
                        saveButtonConfigurations(config);
                        populateButtonConfigs();
                        applyButtonConfigurations();
                        showNotification('Configuration imported from file.');
                    } else {
                        showNotification('Invalid configuration file.');
                    }
                } catch (err) {
                    showNotification('Error: Invalid JSON.');
                }
            };
            reader.readAsText(file);
        };
        input.click();
    }

    function exportConfig() {
        const config = getButtonConfigurations();
        const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'chatButtonConfig.json';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
        showNotification('Configuration exported to file.');
    }

    function updateCharCounter() {
        const textArea = document.getElementById('button-text-content');
        if (!textArea) return;
        const counter = document.getElementById('char-counter');
        if (!counter) return;
        counter.textContent = textArea.value.length;
    }

    function highlightButton(index) {
        const configsContainer = document.getElementById('button-configs');
        const buttonDiv = configsContainer.querySelector(`.draggable[data-index="${index}"]`);
        if (buttonDiv) {
            buttonDiv.classList.add('highlight');
            buttonDiv.scrollIntoView({ behavior: 'smooth', block: 'center' });
            setTimeout(() => {
                buttonDiv.classList.remove('highlight');
            }, 2000);
        }
    }

    addCSS(buttonCSS);

    const chatContainerObserver = new MutationObserver(function() {
        createConfigButton();
        applyButtonConfigurations();
        applyRecentButtonClass();
    });

    const chatContainer = document.querySelector('#chatRoot');
    if (chatContainer) {
        chatContainerObserver.observe(chatContainer, { childList: true, subtree: true });
    }

    applyButtonConfigurations();
    applyRecentButtonClass();
})();