Greasy Fork

Greasy Fork is available in English.

Discord Midjourney 参数面板

在 Discord 中添加 Midjourney 参数设置面板,支持完整卡片式 UI 和最新参数功能(⚠️⚠️⚠️需开启开发者模式)

当前为 2025-05-17 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Discord Midjourney 参数面板
// @namespace    https://github.com/cwser
// @version      0.2.8
// @license      MIT
// @description  在 Discord 中添加 Midjourney 参数设置面板,支持完整卡片式 UI 和最新参数功能(⚠️⚠️⚠️需开启开发者模式)
// @author       cwser
// @match        https://discord.com/*
// @icon         https://www.midjourney.com/favicon.ico
// @grant        unsafeWindow
// @supportURL   https://github.com/cwser
// @homepageURL  https://github.com/cwser
// ==/UserScript==
(function() {
    'use strict';
// 参数定义
    let params = {
        prompt: '',
        ar: '1:1',
        stylize: 100,
        weird: 0,
        chaos: 0,
        mode: 'standard',
        version: 'v7',
        speed: 'relax',
        draft: false,
        noPrompt: '',
        cref: [],
        sref: [],
        oref: [],
        iref: [], // iref 似乎未在UI中使用,但保留定义
        directImages: [],
        tile: false,
        seed: '',
        quality: 1,
        stop: 100,
        visibility: '',
        personalParams: '',
        r: 1
    };

    // 主题相关变量
    let currentThemeMode = 'discord'; // 选项: 'light', 'dark', 'discord', 'system'
    const themeStorageKey = 'mjPanelThemePreference_v3'; // 更新存储键
    const themeModes = ['light', 'dark', 'discord', 'system'];
    const themeTextMap = {
        'light': '浅色模式',
        'dark': '深色模式',
        'discord': '跟随Discord',
        'system': '跟随系统'
    };
    const sunIconSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><circle cx="8" cy="8" r="4"/><path d="M8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zM1.61 4.032a.5.5 0 0 1 .707-.707L3.732 4.739a.5.5 0 1 1-.707.707L1.61 4.032zm12.056-.707a.5.5 0 0 1 .707.707l-1.414 1.414a.5.5 0 1 1-.707-.707l1.414-1.414zM8 12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2a.5.5 0 0 1 .5-.5zm-6.39.261a.5.5 0 0 1 .707.707L3.732 11.26a.5.5 0 0 1-.707-.707L1.61 11.968zm12.056.707a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1-.707.707l-1.414-1.414zM0 8a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1H.5A.5.5 0 0 1 0 8zm12 0a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5z"/></svg>`;
    const moonIconSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"/><path d="M10.794 3.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387a1.734 1.734 0 0 0-1.097 1.097l-.387 1.162a.217.217 0 0 1-.412 0l-.387-1.162A1.734 1.734 0 0 0 9.312 6.19l-1.162-.387a.217.217 0 0 1 0-.412l1.162.387a1.734 1.734 0 0 0 1.097-1.097l.387-1.162zM13.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.156 1.156 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.156 1.156 0 0 0-.732-.732l-.774-.258a.145.145 0 0 1 0-.274l.774.258c.346.115.617-.386.732-.732L13.863.1z"/></svg>`;
    const discordIconSVG = `<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.488c-1.54-.83-3.263-1.463-5.086-1.854a.934.934 0 00-1.003.693c-.21 1.207-.662 2.343-1.204 3.392-2.816-.087-4.804-1.53-4.804-1.53s-.103.2-.186.377C7.659 7.992 7.136 9.31 7.136 9.31s-1.482-.532-2.884-1.318c0 0-1.19 3.204 2.42 6.03 0 0-1.806 1.27-3.68 1.744a17.56 17.56 0 003.032 1.22c1.45.463 2.938.717 4.465.717 1.526 0 3.016-.254 4.465-.717.046-.016.09-.03.135-.046l.004-.002c.03-.01.06-.018.09-.027.08-.026.157-.05.237-.078.068-.025.136-.05.203-.076.085-.034.17-.066.253-.1.07-.03.14-.06.208-.09.087-.04.173-.078.26-.118.062-.03.124-.06.185-.09.09-.046.18-.09.268-.14.06-.034.12-.07.178-.1.092-.05.183-.1.273-.156.053-.033.106-.065.158-.1.088-.055.175-.11.26-.17.046-.03.092-.06.137-.093.082-.06.163-.12.242-.185.04-.03.08-.06.118-.09.075-.062.148-.124.22-.188.035-.03.068-.06.103-.09.067-.06.132-.12.196-.183.026-.025.05-.05.076-.075.168-.16.33-.322.488-.488.093-.1.184-.2.27-.3.027-.03.053-.06.078-.09.13-.15.255-.3.375-.456.023-.03.046-.06.067-.09.102-.14.2-.28.293-.42.018-.028.036-.055.052-.083.078-.13.15-.26.218-.39.01-.02.02-.04.03-.06.06-.11.112-.22.162-.33.005-.01.01-.02.015-.03.044-.1.082-.19.118-.29.002-.006.004-.01.005-.016.03-.08.056-.16.08-.24.022-.07.04-.14.056-.21.015-.06.027-.12.038-.18.01-.05.018-.09.025-.14.006-.04.01-.08.014-.12.003-.03.005-.06.006-.09.002-.04.002-.07 0-.11s0-.03-.002-.045c-.06-1.597-.27-3.143-.62-4.618zm-4.603 7.06c-1.232 0-2.232-1.022-2.232-2.282s.998-2.282 2.232-2.282c1.232 0 2.232 1.022 2.232 2.282s-1.002 2.282-2.232 2.282zm-5.94-2.282c0 1.26.998 2.282 2.232 2.282s2.232-1.022 2.232-2.282S10.94 7.026 9.707 7.026c-1.232 0-2.232 1.022-2.232 2.282z"/></svg>`;
    const systemIconSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M5 4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5zm-.5 7.5A.5.5 0 0 1 4 11V5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H4.5z"/><path d="M1.5 2A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13zM1 3.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 .5.5v9a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-9z"/></svg>`;

    const themeIcons = {
        'light': sunIconSVG,
        'dark': moonIconSVG,
        'discord': discordIconSVG,
        'system': systemIconSVG
    };

    let systemThemeMediaQuery = null;
    let discordThemeObserver = null;

// 定义权重参数前缀的映射
    const weightPrefixes = {
        'cref': '--cw',
        'sref': '--sw',
        'oref': '--ow',
        'directImages': '--iw'
    };

// 显示 Toast 提示
    function showToast(message) {
        const toast = document.createElement('div');
        toast.textContent = message;
        toast.className = 'mj-toast'; // 使用类进行样式化
        toast.style.cssText = `transform: translateY(-20px); opacity: 0;`; // 初始状态,CSS会覆盖
        document.body.appendChild(toast);
        // 触发入场动画
        setTimeout(() => { toast.style.transform = 'translateY(0)'; toast.style.opacity = '1'; }, 10);
        // 触发离场动画并在动画结束后移除
        setTimeout(() => {
            toast.style.transform = 'translateY(-20px)'; toast.style.opacity = '0';
            setTimeout(() => { if (document.body.contains(toast)) document.body.removeChild(toast); }, 300);
        }, 2000);
    }

// 创建设置按钮
    function createSettingButton() {
        const button = document.createElement('button');
        button.textContent = 'MJ参数';
        button.id = 'mj-floating-settings-button';
        button.addEventListener('click', toggleControlPanel);
        document.body.appendChild(button);
        button.addEventListener('mouseenter', () => button.style.transform = 'scale(1.05)');
        button.addEventListener('mouseleave', () => button.style.transform = 'scale(1)');
    }

// 切换控制面板显示/隐藏
    function toggleControlPanel() {
        const panel = document.getElementById('mj-control-panel');
        if (panel) {
            if (panel.style.display === 'none') {
                panel.style.display = 'block'; panel.style.opacity = '0'; panel.style.transform = 'translateY(10px)';
                setTimeout(() => { panel.style.opacity = '1'; panel.style.transform = 'translateY(0)'; }, 10); // 入场动画
            } else {
                const themeMenu = document.getElementById('theme-options-menu');
                if (themeMenu) themeMenu.style.display = 'none'; // 关闭主题菜单
                panel.style.opacity = '0'; panel.style.transform = 'translateY(10px)'; // 离场动画
                setTimeout(() => { panel.style.display = 'none'; }, 200); // 动画完成后隐藏
            }
        }
    }

// 重置参数为默认值
    function resetParams() {
        params = {
            prompt: '', ar: '1:1', stylize: 100, weird: 0, chaos: 0, mode: 'standard',
            version: 'v7', speed: 'relax', draft: false, noPrompt: '', cref: [],
            sref: [], oref: [], iref: [], directImages: [], tile: false, seed: '',
            quality: 1, stop: 100, visibility: '', personalParams: '', r: 1
        };
    }

// 更新最终的提示词参数字符串
    function updatePromptParams() {
        const { prompt, ar, stylize, weird, chaos, mode, draft, noPrompt, version, cref, sref, speed, oref, directImages, tile, seed, quality, stop, visibility, personalParams } = params;
        const otherParts = [
            `--ar ${ar}`, `--s ${stylize}`,
            weird !== 0 ? `--w ${weird}` : '', chaos !== 0 ? `--c ${chaos}` : '',
            mode !== 'standard' ? `--${mode}` : '', draft ? '--draft' : '',
            noPrompt ? `--no ${noPrompt}` : '',
            version.startsWith('niji') ? `--niji ${version.replace('niji', '')}` : `--v ${version.replace('v', '')}`,
            speed !== 'relax' ? `--${speed}` : '', tile ? '--tile' : '',
            seed ? `--seed ${seed}` : '', quality !== 1 ? `--q ${quality}` : '', // 只有非默认值才添加
            stop !== 100 ? `--stop ${stop}` : '', visibility ? `--${visibility}` : '', // public 或 stealth
            personalParams ? `--p ${personalParams}` : '', params.r > 1 ? `--r ${params.r}` : ''
        ];
        const formatImageWithWeight = (url, weight, prefix) => `${url}${weight && weight.trim() !== '' ? ` ${prefix} ${weight.trim()}` : ''}`;
        const directImageUrls = directImages.map(item => formatImageWithWeight(item.url, item.weight, '--iw')).join(' ');
        const promptField = document.getElementById('prompt-params');
        if (promptField) {
            const allParts = [
                directImageUrls,
                prompt.trim(),
                ...cref.map(item => `--cref ${formatImageWithWeight(item.url, item.weight, '--cw')}`),
                ...sref.map(item => `--sref ${formatImageWithWeight(item.url, item.weight, '--sw')}`),
                ...oref.map(item => `--oref ${formatImageWithWeight(item.url, item.weight, '--ow')}`),
                ...otherParts.filter(Boolean)
            ].filter(Boolean);
            promptField.value = allParts.join(' ').trim();
        }
    }

    // 获取实际生效的暗黑模式状态
    function getEffectiveDarkModeState() {
        switch (currentThemeMode) {
            case 'light': return false;
            case 'dark': return true;
            case 'discord': return document.documentElement.classList.contains('theme-dark');
            case 'system':
                return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
            default:
                return document.documentElement.classList.contains('theme-dark');
        }
    }

    // 应用当前主题
    function applyCurrentTheme() {
        const panel = document.getElementById('mj-control-panel');
        if (!panel) return;

        const effectiveDarkMode = getEffectiveDarkModeState();
        panel.classList.toggle('dark-mode', effectiveDarkMode);
        localStorage.setItem(themeStorageKey, currentThemeMode);

        const themeTriggerButton = document.getElementById('theme-dropdown-trigger');
        const themeTriggerIcon = document.getElementById('theme-trigger-icon');
        const themeTriggerText = document.getElementById('theme-trigger-text');

        if (themeTriggerIcon) {
            let iconToShow = themeIcons[currentThemeMode] || sunIconSVG;
            // If discord or system, show actual light/dark icon
            if (currentThemeMode === 'discord' || currentThemeMode === 'system') {
                iconToShow = effectiveDarkMode ? moonIconSVG : sunIconSVG;
            }
            themeTriggerIcon.innerHTML = iconToShow;
        }
        if (themeTriggerText) {
            themeTriggerText.textContent = themeTextMap[currentThemeMode] || '未知主题';
        }
        if (themeTriggerButton) {
            themeTriggerButton.title = `切换主题 (当前: ${themeTextMap[currentThemeMode]})`;
        }

        // 更新主题菜单中选项的激活状态
        const themeOptions = document.querySelectorAll('#theme-options-menu button');
        themeOptions.forEach(opt => {
            opt.classList.toggle('active', opt.dataset.theme === currentThemeMode);
        });


        refreshPreviews();
        setInitialActiveButtons();
        updateToggleVisuals('tile-toggle-switch', 'tile');
        updateToggleVisuals('draft-toggle-switch', 'draft');
        setupDynamicThemeListeners();
    }

    // 处理系统主题变化
    function handleSystemThemeChange() {
        if (currentThemeMode === 'system') applyCurrentTheme();
    }

    // 处理Discord主题变化
    function handleDiscordThemeChange(mutationsList) {
         if (currentThemeMode === 'discord') {
            for (const mutation of mutationsList) {
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    applyCurrentTheme();
                    break;
                }
            }
        }
    }

    // 设置动态主题监听器
    function setupDynamicThemeListeners() {
        if (systemThemeMediaQuery) {
            systemThemeMediaQuery.removeEventListener ? systemThemeMediaQuery.removeEventListener('change', handleSystemThemeChange) : systemThemeMediaQuery.removeListener(handleSystemThemeChange);
            systemThemeMediaQuery = null;
        }
        if (discordThemeObserver) {
            discordThemeObserver.disconnect();
            discordThemeObserver = null;
        }

        if (currentThemeMode === 'system' && window.matchMedia) {
            systemThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
            systemThemeMediaQuery.addEventListener ? systemThemeMediaQuery.addEventListener('change', handleSystemThemeChange) : systemThemeMediaQuery.addListener(handleSystemThemeChange);
        } else if (currentThemeMode === 'discord' && typeof MutationObserver !== "undefined") {
            discordThemeObserver = new MutationObserver(handleDiscordThemeChange);
            discordThemeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
        }
    }

// 创建控制面板HTML结构
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'mj-control-panel';
        panel.style.cssText = `
            display: none; position: fixed; right: 20px; bottom: 80px;
            width: 1080px; max-width: calc(100% - 40px);
            border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
            padding: 20px; z-index: 10000; border: 1px solid #E5E7EB;
            max-height: 90vh; overflow-y: auto; font-family: sans-serif;
            transition: opacity 0.2s ease, transform 0.2s ease;
        `;
        panel.innerHTML = `
            <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:20px;">
                <h3 class="panel-title" style="margin:0; font-size:18px; font-weight:600;">Midjourney 参数设置</h3>
                <div class="panel-divider" style="flex:1; height:1px; margin:0 16px;"></div>
                <div style="position:relative;"> <button id="theme-dropdown-trigger" title="切换主题模式" class="theme-trigger-btn">
                        <span id="theme-trigger-icon" style="display: inline-flex; align-items: center; margin-right: 6px;"></span>
                        <span id="theme-trigger-text"></span>
                    </button>
                    <div id="theme-options-menu" class="theme-options-menu" style="display:none;">
                        <button data-theme="light" class="theme-option-button">${themeIcons.light} ${themeTextMap.light}</button>
                        <button data-theme="dark" class="theme-option-button">${themeIcons.dark} ${themeTextMap.dark}</button>
                        <button data-theme="discord" class="theme-option-button">${themeIcons.discord} ${themeTextMap.discord}</button>
                        <button data-theme="system" class="theme-option-button">${themeIcons.system} ${themeTextMap.system}</button>
                    </div>
                </div>
            </div>
            <div style="display:grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap:20px;">
                <div class="panel-section">
                    <p class="section-title">图片尺寸 (--ar)</p>
                    <div style="display:flex; align-items:center; gap:20px;">
                        <div style="position:relative; width:100px; height:100px;">
                            <div id="ratio-preview-bg" class="ratio-preview-bg"></div>
                            <div id="ratio-preview" style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:100px; height:100px;">
                                <div id="ratio-box" class="ratio-box">1:1</div>
                            </div>
                        </div>
                        <div style="flex:1;">
                            <div id="size-buttons" style="display:flex; gap:8px; margin-bottom:8px;"></div>
                            <input type="range" id="ratio-slider" min="0" max="10" value="5" style="width:100%;">
                        </div>
                    </div>
                </div>
                <div class="panel-section">
                    <p class="section-title">美学参数</p>
                    <div style="display:flex; flex-direction:column; gap:12px;">
                        <div style="display:flex; align-items:center; justify-content:space-between;">
                            <label for="stylize" style="flex:1; margin-right:12px;">风格化 (--s)</label>
                            <input type="range" id="stylize" name="stylize" min="0" max="1000" value="100" style="flex:3;">
                            <span id="stylize-value" class="param-value-display" style="width:40px; text-align:right;">100</span>
                        </div>
                        <div style="display:flex; align-items:center; justify-content:space-between;">
                            <label for="weird" style="flex:1; margin-right:12px;">奇特化 (--w)</label>
                            <input type="range" id="weird" name="weird" min="0" max="3000" value="0" style="flex:3;">
                            <span id="weird-value" class="param-value-display" style="width:40px; text-align:right;">0</span>
                        </div>
                        <div style="display:flex; align-items:center; justify-content:space-between;">
                            <label for="chaos" style="flex:1; margin-right:12px;">多样性 (--c)</label>
                            <input type="range" id="chaos" name="chaos" min="0" max="100" value="0" style="flex:3;">
                            <span id="chaos-value" class="param-value-display" style="width:40px; text-align:right;">0</span>
                        </div>
                    </div>
                </div>
                <div class="panel-section" style="display: flex; flex-direction: column; gap: 10px;">
                    <p class="section-title">模型设置</p>
                    <div style="display:flex; gap:10px; align-items:center;">
                        <label style="flex:1;">速度
                            <div class="btn-group">
                                <button data-value="relax" class="speed-btn">标准</button>
                                <button data-value="fast" class="speed-btn">快速</button>
                                <button data-value="turbo" class="speed-btn">极速</button>
                            </div>
                        </label>
                        <label style="flex:1;">模式
                            <div class="btn-group">
                                <button data-value="standard" class="mode-btn">标准</button>
                                <button data-value="raw" class="mode-btn">原始</button>
                            </div>
                        </label>
                    </div>
                    <div style="display:flex; gap:10px; align-items:center;">
                        <label style="flex:1;">草稿 (--draft)
                            <div class="toggle-switch" id="draft-toggle-switch">
                                <div class="toggle-dot"></div>
                            </div>
                        </label>
                        <label for="version-select" style="flex:2;">版本 (--v, --niji)
                            <select id="version-select" name="version-select">
                                <option value="v7">v7</option> <option value="v6.1">v6.1</option> <option value="v6">v6</option>
                                <option value="v5.2">v5.2</option> <option value="v5.1">v5.1</option> <option value="v5">v5</option>
                                <option value="v4">v4</option> <option value="v3">v3</option> <option value="v2">v2</option>
                                <option value="v1">v1</option> <option value="niji6">niji6</option> <option value="niji5">niji5</option>
                                <option value="niji4">niji4</option>
                            </select>
                        </label>
                    </div>
                </div>
                <div class="panel-section">
                    <p class="section-title">角色参考 (--cref)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="cref-url" placeholder="粘贴角色图片URL"><input type="number" id="cref-weight" placeholder="权重 (--cw)">
                    </div>
                    <button id="cref-add" class="action-button">添加</button>
                    <div id="cref-preview" class="ref-preview-container"></div>
                </div>
                <div class="panel-section">
                    <p class="section-title">风格参考 (--sref)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                         <input type="text" id="sref-url" placeholder="图片URL, 'random'或数字码"><input type="number" id="sref-weight" placeholder="权重 (--sw)">
                    </div>
                    <button id="sref-add" class="action-button">添加</button>
                    <div id="sref-preview" class="ref-preview-container"></div>
                </div>
                <div class="panel-section">
                    <p class="section-title">全方位参考 (--oref)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="oref-url" placeholder="粘贴全方位参考图片URL"><input type="number" id="oref-weight" placeholder="权重 (--ow)">
                    </div>
                    <button id="oref-add" class="action-button">添加</button>
                    <div id="oref-preview" class="ref-preview-container"></div>
                </div>
                <div class="panel-section">
                    <p class="section-title">图像参考 (URL --iw)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="direct-image-url" placeholder="粘贴图像URL"><input type="number" id="direct-image-weight" placeholder="权重 (--iw)">
                    </div>
                    <button id="direct-image-add" class="action-button">添加</button>
                    <div id="direct-image-preview" class="ref-preview-container"></div>
                </div>
                <div class="panel-section" style="grid-column: span 2;">
                    <p class="section-title">更多参数</p>
                    <div style="display:grid; grid-template-columns: 1fr 1fr; gap:16px;">
                        <div>
                            <div style="display:flex; align-items:center; gap:8px; margin-bottom:16px;">
                                <div class="toggle-switch" id="tile-toggle-switch"><div class="toggle-dot"></div></div>
                                <label>重复图案 (--tile)</label>
                            </div>
                            <div style="display:flex; align-items:center; gap:8px; margin-bottom:16px;">
                                <label for="seed-input">种子 (--seed)</label>
                                <input type="number" id="seed-input" name="seed-input" placeholder="0-4294967295" min="0" max="4294967295">
                            </div>
                            <div style="display:flex; align-items:center; gap:8px; margin-bottom:16px;">
                                <label for="personal-params">个性化 (--p)</label>
                                <input type="text" id="personal-params" name="personal-params" placeholder="输入个性化参数">
                            </div>
                        </div>
                        <div>
                            <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:16px;">
                                <label for="quality-slider">质量 (--q)</label>
                                <input type="range" id="quality-slider" name="quality-slider" min="0" max="4" step="1" value="2"><span id="quality-value" class="param-value-display">1</span>
                            </div>
                            <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:16px;">
                                <label for="stop-slider">停止 (--stop)</label>
                                <input type="range" id="stop-slider" name="stop-slider" min="10" max="100" step="1" value="100"><span id="stop-value" class="param-value-display">100</span>
                            </div>
                             <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:16px;">
                                <label for="r-slider">批量任务 (--r)</label>
                                <input type="range" id="r-slider" name="r-slider" min="1" max="10" value="1"><span id="r-value" class="param-value-display">1</span>
                            </div>
                        </div>
                    </div>
                     <p class="section-title" style="margin-top:10px;">可见性 (--public, --stealth)</p>
                    <div class="btn-group"> <button data-value="" class="visibility-btn">默认</button>
                        <button data-value="public" class="visibility-btn">公开</button>
                        <button data-value="stealth" class="visibility-btn">隐身</button>
                    </div>
                </div>
            </div>
            <div style="margin-top:20px; border-top:1px solid; padding-top:16px;" class="results-section-divider">
                <div style="display:flex; gap:10px;">
                    <div style="flex:1;">
                        <p class="section-title">提示词</p>
                        <textarea id="main-prompt" placeholder="输入主要提示词..."></textarea>
                    </div>
                    <div style="flex:1;">
                        <p class="section-title">排除词 (--no)</p>
                        <textarea id="no-prompt" placeholder="输入需要排除的元素,多个用空格分隔"></textarea>
                    </div>
                    <div style="flex:1;">
                        <p class="section-title">最终参数</p>
                        <textarea id="prompt-params" readonly></textarea>
                    </div>
                </div>
            </div>
            <div style="margin-top:16px; display:flex; gap:10px;">
                <button id="copy-btn" class="action-button-primary">拷贝参数</button>
                <button id="clear-btn" class="action-button-secondary">清空参数</button>
            </div>
        `;
        document.body.appendChild(panel);

        const savedTheme = localStorage.getItem(themeStorageKey);
        if (savedTheme && themeModes.includes(savedTheme)) {
            currentThemeMode = savedTheme;
        } else {
            currentThemeMode = 'discord';
        }

        bindControlEvents();
        applyCurrentTheme();

        // 点击外部关闭主题菜单
        document.addEventListener('click', function(event) {
            const themeMenu = document.getElementById('theme-options-menu');
            const themeTrigger = document.getElementById('theme-dropdown-trigger');
            if (themeMenu && themeTrigger && themeMenu.style.display === 'block') {
                if (!themeMenu.contains(event.target) && !themeTrigger.contains(event.target)) {
                    themeMenu.style.display = 'none';
                }
            }
        });
    }


// 设置按钮的激活类。CSS处理特定主题的外观。
    function setInitialActiveButtons() {
        const buttonGroups = [
            { className: 'speed-btn', param: 'speed', defaultValue: 'relax' },
            { className: 'mode-btn', param: 'mode', defaultValue: 'standard' },
            { className: 'visibility-btn', param: 'visibility', defaultValue: '' } // visibility按钮现在会使用.btn-group样式
        ];
        buttonGroups.forEach(group => {
            const buttons = document.querySelectorAll(`#mj-control-panel .${group.className}`);
            let currentParamValue = params[group.param] === undefined ? group.defaultValue : params[group.param];
            buttons.forEach(btn => {
                btn.classList.toggle('active', btn.dataset.value === currentParamValue);
            });
        });
        const ratioSlider = document.getElementById('ratio-slider');
        if (ratioSlider) ratioSlider.dispatchEvent(new Event('input'));
    }

// 通过添加/移除 'active' 类来更新切换开关的视觉效果。CSS处理外观。
    function updateToggleVisuals(switchId, property) {
        const switchEl = document.getElementById(switchId);
        if (!switchEl) return;
        switchEl.classList.toggle('active', !!params[property]);
    }

    // 设置参考图/代码区域的功能
    const setupRefSection = (idPrefix, paramKey) => {
        const $ = id => document.getElementById(id);
        const addBtn = $(`${idPrefix}-add`);
        const urlInput = $(`${idPrefix}-url`);
        const weightInput = $(`${idPrefix}-weight`);
        const previewContainerId = `${idPrefix}-preview`;

        if (!addBtn || !urlInput || !weightInput) return;

        addBtn.onclick = () => {
            const url = urlInput.value.trim();
            const weight = weightInput.value.trim();
            let toastMessage = `请输入${paramKey === 'sref' ? 'URL或代码' : 'URL'}`;
            if (!url) { showToast(toastMessage); return; }

            const isImageUrl = /^https?:\/\/.+\.(jpg|jpeg|png|webp|gif|svg|bmp|tiff|ico)(\?.*)?$/i.test(url);
            const isSrefCode = paramKey === 'sref' && (/^\d+$/.test(url) || url.toLowerCase() === 'random');

            if (paramKey !== 'sref' && !isImageUrl) { showToast('请输入有效的图片URL'); return; }
            if (paramKey === 'sref' && !isImageUrl && !isSrefCode) { showToast("sref请输入有效图片URL, 'random'或数字代码"); return; }

            const targetArray = params[paramKey];
            if (!Array.isArray(targetArray)) return;

            const itemUrl = (paramKey === 'sref' && isSrefCode) ? (url.toLowerCase() === 'random' ? 'random' : url) : url;

            if (!targetArray.some(item => item.url === itemUrl)) {
                targetArray.push({ url: itemUrl, weight: weight });
                const currentWeightPrefix = weightPrefixes[paramKey];
                if (paramKey === 'sref' && isSrefCode) {
                    addPreviewSrefCode(previewContainerId, itemUrl, weight);
                } else {
                    addPreviewImage(previewContainerId, itemUrl, weight, paramKey, currentWeightPrefix);
                }
                urlInput.value = ''; weightInput.value = '';
                updatePromptParams();
            } else {
                showToast(`该${(paramKey === 'sref' && isSrefCode) ? '代码' : 'URL'}已添加`);
            }
        };
    };

    // 绑定控制面板的事件
    function bindControlEvents() {
        const $ = id => document.getElementById(id);

        // 主题下拉菜单逻辑
        const themeTriggerButton = $('theme-dropdown-trigger');
        const themeOptionsMenu = $('theme-options-menu');
        if (themeTriggerButton && themeOptionsMenu) {
            themeTriggerButton.addEventListener('click', (event) => {
                event.stopPropagation(); // 防止触发全局点击监听器
                themeOptionsMenu.style.display = themeOptionsMenu.style.display === 'none' ? 'block' : 'none';
            });

            document.querySelectorAll('.theme-option-button').forEach(button => {
                button.addEventListener('click', () => {
                    currentThemeMode = button.dataset.theme;
                    applyCurrentTheme();
                    themeOptionsMenu.style.display = 'none';
                });
            });
        }


        if ($('main-prompt')) $('main-prompt').oninput = e => { params.prompt = e.target.value; updatePromptParams(); };

        const bindSliderEvent = (id, property, displayId = null, isFloat = false) => {
            const slider = $(id); if (!slider) return;
            slider.oninput = e => {
                const value = isFloat ? parseFloat(e.target.value) : parseInt(e.target.value, 10);
                params[property] = value;
                if (displayId && $(displayId)) $(displayId).textContent = e.target.value;
                updatePromptParams();
            };
        };
        bindSliderEvent('stylize', 'stylize', 'stylize-value');
        bindSliderEvent('weird', 'weird', 'weird-value');
        bindSliderEvent('chaos', 'chaos', 'chaos-value');
        bindSliderEvent('stop-slider', 'stop', 'stop-value');
        bindSliderEvent('r-slider', 'r', 'r-value');

        const qualitySlider = $('quality-slider'); const qualityValueDisplay = $('quality-value');
        const qualityMap = [0.25, 0.5, 1, 2, 4];
        if (qualitySlider && qualityValueDisplay) {
            const initialQualityValue = params.quality;
            const initialSliderIndex = qualityMap.indexOf(initialQualityValue);
            if (initialSliderIndex !== -1) {
                qualitySlider.value = initialSliderIndex;
                qualityValueDisplay.textContent = initialQualityValue;
            } else {
                params.quality = 1;
                qualitySlider.value = qualityMap.indexOf(1);
                qualityValueDisplay.textContent = params.quality;
            }
            qualitySlider.oninput = e => {
                const sliderIndex = parseInt(e.target.value, 10);
                if (sliderIndex >= 0 && sliderIndex < qualityMap.length) {
                    params.quality = qualityMap[sliderIndex];
                    if (qualityValueDisplay) qualityValueDisplay.textContent = params.quality;
                    updatePromptParams();
                }
            };
        }

        const bindRadioGroup = (groupClass, property) => {
            document.querySelectorAll(`#mj-control-panel .${groupClass}`).forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll(`#mj-control-panel .${groupClass}`).forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    params[property] = btn.dataset.value;
                    updatePromptParams();
                });
            });
        };
        bindRadioGroup('speed-btn', 'speed');
        bindRadioGroup('mode-btn', 'mode');
        bindRadioGroup('visibility-btn', 'visibility');

        const bindToggleSwitchEvent = (switchId, property) => {
            const switchEl = $(switchId); if (!switchEl) return;
            switchEl.addEventListener('click', () => {
                params[property] = !params[property];
                updateToggleVisuals(switchId, property);
                updatePromptParams();
            });
        };
        bindToggleSwitchEvent('tile-toggle-switch', 'tile');
        bindToggleSwitchEvent('draft-toggle-switch', 'draft');

        if ($('version-select')) $('version-select').onchange = e => { params.version = e.target.value; updatePromptParams(); };
        if ($('no-prompt')) $('no-prompt').oninput = e => { params.noPrompt = e.target.value.trim(); updatePromptParams(); };

        if ($('copy-btn')) {
            $('copy-btn').onclick = () => {
                const textarea = $('prompt-params');
                if (!textarea || !textarea.value) { showToast('没有参数可以拷贝'); return; }
                textarea.select();
                try {
                    if (navigator.clipboard && navigator.clipboard.writeText) {
                        navigator.clipboard.writeText(textarea.value)
                            .then(() => showToast('参数已复制!'))
                            .catch(() => { showToast('复制失败!请尝试手动复制。'); legacyCopy(textarea); });
                    } else {
                        legacyCopy(textarea);
                    }
                } catch (err) {
                    console.error('复制尝试失败:', err);
                }
            };
        }
        function legacyCopy(textareaElement) {
            try {
                const successful = document.execCommand('copy');
                showToast(successful ? '参数已复制 (兼容模式)!' : '复制失败 (兼容模式)!请手动复制。');
            } catch (err) {
                showToast('复制异常 (兼容模式)!请手动复制。');
            }
        }

        const sizeMap = ['1:2', '9:16', '2:3', '3:4', '5:6', '1:1', '6:5', '4:3', '3:2', '16:9', '2:1'];
        if ($('clear-btn')) {
            $('clear-btn').onclick = () => {
                resetParams();
                if ($('main-prompt')) $('main-prompt').value = params.prompt;
                if ($('stylize')) $('stylize').value = params.stylize; if ($('stylize-value')) $('stylize-value').textContent = params.stylize;
                if ($('weird')) $('weird').value = params.weird; if ($('weird-value')) $('weird-value').textContent = params.weird;
                if ($('chaos')) $('chaos').value = params.chaos; if ($('chaos-value')) $('chaos-value').textContent = params.chaos;
                if ($('version-select')) $('version-select').value = params.version;
                if ($('no-prompt')) $('no-prompt').value = params.noPrompt;

                if ($('ratio-slider')) {
                    const defaultRatioIndex = sizeMap.indexOf(params.ar);
                    $('ratio-slider').value = defaultRatioIndex !== -1 ? defaultRatioIndex : 5;
                    $('ratio-slider').dispatchEvent(new Event('input'));
                }
                ['cref-url', 'cref-weight', 'sref-url', 'sref-weight', 'oref-url', 'oref-weight', 'direct-image-url', 'direct-image-weight']
                    .forEach(id => { if ($(id)) $(id).value = ''; });
                if ($('seed-input')) $('seed-input').value = params.seed;

                if ($('quality-slider')) {
                    const resetSliderIndex = qualityMap.indexOf(params.quality);
                     $('quality-slider').value = resetSliderIndex !== -1 ? resetSliderIndex : qualityMap.indexOf(1);
                     const qvDisplay = $('quality-value');
                     if(qvDisplay) qvDisplay.textContent = params.quality;
                }
                if ($('stop-slider')) $('stop-slider').value = params.stop; if ($('stop-value')) $('stop-value').textContent = params.stop;
                if ($('personal-params')) $('personal-params').value = params.personalParams;
                if ($('r-slider')) $('r-slider').value = params.r; if ($('r-value')) $('r-value').textContent = params.r;

                updateToggleVisuals('tile-toggle-switch', 'tile');
                updateToggleVisuals('draft-toggle-switch', 'draft');
                setInitialActiveButtons();
                refreshPreviews();
                updatePromptParams();
                showToast('所有参数已重置为默认值');
            };
        }

        setupRefSection('cref', 'cref');
        setupRefSection('sref', 'sref');
        setupRefSection('oref', 'oref');
        setupRefSection('direct-image', 'directImages');

        const ratioPresets = { '1:2': { width: 50, height: 100 }, '9:16': { width: 56.25, height: 100 }, '2:3': { width: 66.67, height: 100 }, '3:4': { width: 75, height: 100 }, '5:6': { width: 83.33, height: 100 }, '1:1': { width: 100, height: 100 }, '6:5': { width: 100, height: 83.33 }, '4:3': { width: 100, height: 75 }, '3:2': { width: 100, height: 66.67 }, '16:9': { width: 100, height: 56.25 }, '2:1': { width: 100, height: 50 }};
        const ratioSlider = $('ratio-slider');
        if (ratioSlider) {
            ratioSlider.oninput = e => {
                const ratio = sizeMap[+e.target.value] || '1:1'; params.ar = ratio;
                const box = $('ratio-box'); const preset = ratioPresets[ratio] || { width: 100, height: 100 };
                if(box) { box.style.width = `${preset.width}px`; box.style.height = `${preset.height}px`; box.textContent = ratio; }
                document.querySelectorAll('#size-buttons button').forEach(btn => {
                    btn.classList.toggle('active', btn.dataset.value === ratio);
                });
                updatePromptParams();
            };
        }

        const sizeButtonGroup = $('size-buttons');
        if (sizeButtonGroup) {
            const presetMap = { '纵向': '1:2', '正方形': '1:1', '横向': '2:1' };
            ['纵向', '正方形', '横向'].forEach((label) => {
                const btn = document.createElement('button'); btn.textContent = label;
                btn.dataset.value = presetMap[label];
                btn.onclick = () => {
                    const ratio = presetMap[label]; const sliderIndex = sizeMap.indexOf(ratio);
                    if (sliderIndex !== -1 && ratioSlider) {
                        ratioSlider.value = sliderIndex;
                        ratioSlider.dispatchEvent(new Event('input'));
                    }
                };
                sizeButtonGroup.appendChild(btn);
            });
        }

        if ($('seed-input')) {
            $('seed-input').oninput = e => {
                const value = e.target.value.trim();
                if (/^\d*$/.test(value) && (value === '' || (parseInt(value) >= 0 && parseInt(value) <= 4294967295))) {
                    params.seed = value;
                } else {
                    e.target.value = params.seed;
                }
                updatePromptParams();
            };
        }
        if ($('personal-params')) $('personal-params').oninput = e => { params.personalParams = e.target.value.trim(); updatePromptParams(); };

        const promptParamsTextarea = $('prompt-params');
        if (promptParamsTextarea) {
            promptParamsTextarea.addEventListener('click', () => {
                if (!promptParamsTextarea.value) { showToast('没有参数可以拷贝'); return; }
                if (navigator.clipboard && navigator.clipboard.writeText) {
                    navigator.clipboard.writeText(promptParamsTextarea.value)
                        .then(() => showToast('参数已复制!'))
                        .catch(() => { showToast('复制失败!'); legacyCopy(promptParamsTextarea);});
                } else {
                    legacyCopy(promptParamsTextarea);
                }
            });
        }

        document.querySelectorAll('#mj-control-panel input[type="text"], #mj-control-panel input[type="number"], #mj-control-panel textarea, #mj-control-panel select').forEach(el => {
            el.addEventListener('focus', (e) => e.target.classList.add('focused'));
            el.addEventListener('blur', (e) => e.target.classList.remove('focused'));
        });

        updateToggleVisuals('tile-toggle-switch', 'tile');
        updateToggleVisuals('draft-toggle-switch', 'draft');
        setInitialActiveButtons();
        if (ratioSlider) {
            const initialRatioIndex = sizeMap.indexOf(params.ar);
            ratioSlider.value = initialRatioIndex !== -1 ? initialRatioIndex : 5;
            ratioSlider.dispatchEvent(new Event('input'));
        }
    }

    // 添加图片预览到容器
    function addPreviewImage(containerId, url, weight, paramKey, currentWeightPrefix) {
        const container = document.getElementById(containerId); if (!container) return;
        const imgContainer = document.createElement('div');
        imgContainer.className = 'ref-image-container';
        imgContainer.style.animation = 'fadeIn 0.3s ease';

        const img = document.createElement('img'); img.src = url;
        img.className = 'ref-image-preview';
        img.onerror = () => {
            const errorDiv = document.createElement('div'); errorDiv.textContent = '无效图';
            errorDiv.className = 'ref-image-error';
            imgContainer.innerHTML = '';
            imgContainer.appendChild(errorDiv);
        };

        const weightBadge = document.createElement('div');
        weightBadge.className = 'ref-weight-badge';
        const wP = currentWeightPrefix ? currentWeightPrefix.replace('--', '') : '';
        weightBadge.textContent = weight && weight.trim() !== '' ? `${wP}:${weight}` : `${wP}:默认`;

        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'ref-delete-btn';
        deleteBtn.innerHTML = '&times;';
        deleteBtn.onclick = function(e) {
            e.stopPropagation();
            imgContainer.style.animation = 'fadeOut 0.2s ease forwards';
            setTimeout(() => {
                const targetArray = params[paramKey];
                if (Array.isArray(targetArray)) {
                    const index = targetArray.findIndex(item => item.url === url);
                    if (index !== -1) {
                        targetArray.splice(index, 1);
                        if (container.contains(imgContainer)) container.removeChild(imgContainer);
                        updatePromptParams();
                    }
                }
            }, 200);
        };
        imgContainer.appendChild(img); imgContainer.appendChild(weightBadge); imgContainer.appendChild(deleteBtn);
        container.appendChild(imgContainer);
    }

    // 添加sref代码预览到容器
    function addPreviewSrefCode(containerId, code, weight) {
        const container = document.getElementById(containerId); if (!container) return;
        const codeContainer = document.createElement('div');
        codeContainer.className = 'ref-code-container';
        codeContainer.style.animation = 'fadeIn 0.3s ease';

        const codeText = document.createElement('span'); codeText.textContent = `sref:${code}`;
        const weightBadge = document.createElement('div');
        weightBadge.className = 'ref-code-weight-badge';
        weightBadge.textContent = weight && weight.trim() !== '' ? `sw:${weight}` : 'sw:默认';

        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'ref-code-delete-btn';
        deleteBtn.innerHTML = '&times;';
        deleteBtn.onclick = function(e) {
            e.stopPropagation(); codeContainer.style.animation = 'fadeOut 0.2s ease forwards';
            setTimeout(() => {
                const index = params.sref.findIndex(item => item.url === code);
                if (index !== -1) {
                    params.sref.splice(index, 1);
                    if (container.contains(codeContainer)) container.removeChild(codeContainer);
                    updatePromptParams();
                }
            }, 200);
        };
        codeContainer.appendChild(codeText); codeContainer.appendChild(weightBadge); codeContainer.appendChild(deleteBtn);
        container.appendChild(codeContainer);
    }

    // 刷新所有参考图/代码的预览区域
    function refreshPreviews() {
        const refTypes = [
            { idPrefix: 'cref', paramKey: 'cref', previewId: 'cref-preview' },
            { idPrefix: 'sref', paramKey: 'sref', previewId: 'sref-preview' },
            { idPrefix: 'oref', paramKey: 'oref', previewId: 'oref-preview' },
            { idPrefix: 'direct-image', paramKey: 'directImages', previewId: 'direct-image-preview' }
        ];
        refTypes.forEach(ref => {
            const container = document.getElementById(ref.previewId); if (!container) return;
            container.innerHTML = '';
            const items = params[ref.paramKey];
            if (items && Array.isArray(items)) {
                items.forEach(item => {
                    const currentWeightPrefix = weightPrefixes[ref.paramKey];
                    if (ref.paramKey === 'sref' && (item.url === 'random' || /^\d+$/.test(item.url))) {
                        addPreviewSrefCode(ref.previewId, item.url, item.weight);
                    } else {
                        addPreviewImage(ref.previewId, item.url, item.weight, ref.paramKey, currentWeightPrefix);
                    }
                });
            }
        });
    }

    // 注入CSS样式
    function injectStyles() {
        const styleSheet = document.createElement("style");
        styleSheet.type = "text/css";
        styleSheet.innerText = `
            /* 入场/出场动画 */
            @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
            @keyframes fadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(5px); } }

            /* MJ参数浮动按钮 */
            #mj-floating-settings-button {
                position: fixed; right: 20px; bottom: 20px; padding: 10px 20px;
                background-color: #5865F2; color: white; border: none; border-radius: 8px;
                cursor: pointer; z-index: 9999; box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                transition: background-color 0.2s ease, transform 0.2s ease; font-family: sans-serif;
            }
            #mj-floating-settings-button:hover { background-color: #4752C4; transform: scale(1.05); }

            /* Toast提示样式 */
            .mj-toast {
                position: fixed; top: 20px; right: 20px; padding: 10px 16px; border-radius: 6px;
                z-index: 99999; transition: all 0.3s ease; font-family: sans-serif;
            }
            #mj-control-panel:not(.dark-mode) ~ body .mj-toast, .mj-toast {
                background: #2B2D31; color: #DCDDDE; box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            }
            #mj-control-panel.dark-mode ~ body .mj-toast {
                 background: #DCDDDE; color: #2B2D31; box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            }

            /* 面板基础样式 */
            #mj-control-panel { background: white; color: #111827; border-color: #E0E0E0; }
            #mj-control-panel .panel-title { color: #111827; }
            #mj-control-panel .panel-divider { background: #e5e7eb; }
            #mj-control-panel .panel-section { background: #f9fafb; padding:16px; border-radius:8px;}
            #mj-control-panel .section-title { margin:0 0 8px 0; font-weight:500; color: #1F2937; }
            #mj-control-panel label, #mj-control-panel .param-value-display { color: #1F2937; }
            #mj-control-panel input[type="text"], #mj-control-panel input[type="number"],
            #mj-control-panel textarea, #mj-control-panel select {
                background: white; color: #111827; border: 1px solid #D1D5DB;
                padding: 6px 10px; border-radius: 6px; box-sizing: border-box;
                transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
                font-size: 14px; /* 统一字体大小 */
            }
            #mj-control-panel select {
                -webkit-appearance: none; /* Remove default Mac/iOS styling */
                -moz-appearance: none; /* Remove default Firefox styling */
                appearance: none; /* Remove default styling */
                background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="%23374151" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>');
                background-repeat: no-repeat;
                background-position: right 0.7em top 50%;
                background-size: 0.8em auto;
                padding-right: 2.5em; /* Make space for the arrow */
            }
            #mj-control-panel input[type="text"].focused, #mj-control-panel input[type="number"].focused,
            #mj-control-panel textarea.focused, #mj-control-panel select.focused { border-color: #4f46e5; }
            #mj-control-panel textarea { resize: vertical; height: 80px; width:100%; padding:10px; }
            #mj-control-panel #prompt-params { background:#f9fafb; cursor:pointer; }
            #mj-control-panel .results-section-divider { border-top-color: #e5e7eb; }

            /* 主题切换触发按钮 */
            #mj-control-panel .theme-trigger-btn {
                padding: 6px 12px; border-radius: 6px; border: 1px solid #D1D5DB;
                background-color: white; color: #1F2937; font-size: 13px;
                cursor: pointer; display: inline-flex; align-items: center;
                transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
            }
            #mj-control-panel .theme-trigger-btn:hover { border-color: #4f46e5; }
            #mj-control-panel .theme-trigger-btn svg { width: 16px; height: 16px; }

            /* 主题选项菜单 */
            #mj-control-panel .theme-options-menu {
                position: absolute; top: calc(100% + 5px); right: 0;
                background-color: white; border: 1px solid #D1D5DB;
                border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);
                z-index: 10010; min-width: 180px; padding: 4px;
            }
            #mj-control-panel .theme-option-button {
                display: flex; align-items: center; width: 100%;
                padding: 8px 12px; text-align: left; background: none; border: none;
                cursor: pointer; font-size: 13px; color: #1F2937; border-radius: 4px;
                transition: background-color 0.15s ease, color 0.15s ease;
            }
            #mj-control-panel .theme-option-button svg { margin-right: 8px; width:16px; height:16px; opacity: 0.7; }
            #mj-control-panel .theme-option-button:hover { background-color: #f0f0f0; }
            #mj-control-panel .theme-option-button.active { background-color: #eef2ff; color: #4338ca; font-weight: 500; }
            #mj-control-panel .theme-option-button.active svg { opacity: 1; }


            /* 比例预览 浅色 */
            #mj-control-panel .ratio-preview-bg { position:absolute; top:0; left:0; width:100px; height:100px; border:2px dashed #d1d5db; border-radius:12px; }
            #mj-control-panel .ratio-box { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); background:#f3f4f6; border:2px solid #374151; border-radius:6px; display:flex; align-items:center; justify-content:center; font-size:12px; color:#374151; padding:2px 4px; min-width:20px; min-height:12px; box-sizing: border-box; }

            /* 滑块 浅色 */
            #mj-control-panel input[type="range"] { -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer; width: 100%;}
            #mj-control-panel input[type="range"]::-webkit-slider-runnable-track { background: #E5E7EB; height: 0.4rem; border-radius: 0.2rem; }
            #mj-control-panel input[type="range"]::-moz-range-track { background: #E5E7EB; height: 0.4rem; border-radius: 0.2rem; }
            #mj-control-panel input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; margin-top: -0.3rem; background-color: #4f46e5; height: 1rem; width: 1rem; border-radius: 50%; border: 1px solid #3730a3; }
            #mj-control-panel input[type="range"]::-moz-range-thumb { border: none; border-radius: 50%; background-color: #4f46e5; height: 1rem; width: 1rem; border: 1px solid #3730a3;}

            /* 按钮组 浅色 (通用) */
            #mj-control-panel .btn-group { display:flex; border-radius:6px; overflow:hidden; border:1px solid #d1d5db; }
            #mj-control-panel .btn-group button { flex:1; padding:6px 10px; background:white; border:none; cursor:pointer; color: #374151; transition: background-color 0.2s, color 0.2s; font-size: 13px;}
            #mj-control-panel .btn-group button:not(:last-child) { border-right: 1px solid #d1d5db; }
            #mj-control-panel .btn-group button.active { background: #4f46e5; color: white; }
            /* #mj-control-panel .visibility-btn-group button.active { border-color: #4f46e5; background: #eef2ff; color: #4338ca; } */ /* No longer needed with unified btn-group */


            /* 切换开关 浅色 */
            #mj-control-panel .toggle-switch { position:relative; width:40px; height:20px; border-radius:10px; background:#e5e7eb; cursor:pointer; margin-top: 4px; transition: background-color 0.2s ease; }
            #mj-control-panel .toggle-switch .toggle-dot { position:absolute; top:2px; left:2px; width:16px; height:16px; border-radius:50%; background:white; box-shadow:0 1px 3px rgba(0,0,0,0.2); transition:all 0.2s ease; }
            #mj-control-panel .toggle-switch.active { background:#4f46e5; }
            #mj-control-panel .toggle-switch.active .toggle-dot { transform: translateX(20px); }

            /* 操作按钮 浅色 */
            #mj-control-panel .action-button, #mj-control-panel .action-button-primary, #mj-control-panel .action-button-secondary { padding:4px 8px; border:none; border-radius:4px; cursor:pointer; transition:all 0.2s ease; }
            #mj-control-panel .action-button { background:#4f46e5; color:white; }
            #mj-control-panel .action-button:hover { background:#4338CA; }
            #mj-control-panel .action-button-primary { flex:1; padding:8px; border-radius:6px; background:#4f46e5; color:white; }
            #mj-control-panel .action-button-primary:hover { background:#4338CA; }
            #mj-control-panel .action-button-secondary { flex:1; padding:8px; border-radius:6px; background:#E5E7EB; color:#374151; border: 1px solid #D1D5DB; }
            #mj-control-panel .action-button-secondary:hover { background:#D1D5DB; }
            #mj-control-panel #size-buttons button { padding: 4px 12px; border-radius: 6px; cursor: pointer; transition: all 0.2s ease; background: white; color: #374151; border: 1px solid #D1D5DB; font-size: 13px;}
            #mj-control-panel #size-buttons button.active { background: #4f46e5; color: white; border-color: #4f46e5; }
            #mj-control-panel #size-buttons button:hover:not(.active) { background: #f0f0f0; }


            /* 参考图预览 浅色 */
            #mj-control-panel .ref-preview-container { margin-top:10px; display:flex; flex-wrap:wrap; gap:8px; }
            #mj-control-panel .ref-image-container { position: relative; margin: 4px; }
            #mj-control-panel .ref-image-preview { width: 60px; height: 60px; object-fit: cover; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); border: 1px solid #E5E7EB; transition: all 0.2s ease; }
            #mj-control-panel .ref-image-preview:hover { transform: scale(1.05); box-shadow: 0 2px 6px rgba(0,0,0,0.15); }
            #mj-control-panel .ref-image-error { width:60px; height:60px; display:flex; align-items:center; justify-content:center; border-radius:4px; font-size:10px; text-align:center; background: #F3F4F6; color: #757575; border: 1px solid #E5E7EB; }
            #mj-control-panel .ref-weight-badge { position: absolute; bottom: 0; left: 0; background: rgba(255,255,255,0.8); color: #374151; font-size: 10px; padding: 1px 3px; border-radius: 0 4px 0 0; border-top: 1px solid #4f46e5; border-right: 1px solid #4f46e5; }
            #mj-control-panel .ref-delete-btn { position: absolute; top: -5px; right: -5px; background: rgba(239, 68, 68, 0.85); color: white; border: none; border-radius: 50%; width: 18px; height: 18px; font-size: 12px; line-height: 18px; text-align:center; cursor:pointer; transition:all 0.2s ease; opacity: 0.8; display:flex; align-items:center; justify-content:center; box-shadow: 0 1px 2px rgba(0,0,0,0.2); }
            #mj-control-panel .ref-delete-btn:hover { opacity: 1; transform: scale(1.1); background: rgb(220, 38, 38); }

            #mj-control-panel .ref-code-container { position: relative; margin: 4px; border-radius: 4px; padding: 6px 10px; display: inline-flex; align-items: center; font-family: monospace; font-size: 12px; background: #F3F4F6; color: #111827; border: 1px solid #E0E0E0; }
            #mj-control-panel .ref-code-weight-badge { margin-left: 8px; font-size: 10px; padding: 2px 4px; border-radius: 3px; background: rgba(79, 70, 229, 0.1); color: #4f46e5; }
            #mj-control-panel .ref-code-delete-btn { margin-left: 10px; border: none; border-radius: 4px; padding: 2px 5px; font-size: 10px; line-height:1; cursor:pointer; transition:all 0.2s ease; background: rgba(239, 68, 68, 0.1); color: #ef4444; }
            #mj-control-panel .ref-code-delete-btn:hover { background: rgba(239, 68, 68, 0.25); }


            /* 暗黑模式样式 */
            #mj-control-panel.dark-mode { background: #2B2D31; color: #DCDDDE; border-color: #202225; }
            #mj-control-panel.dark-mode .panel-title { color: #DCDDDE; }
            #mj-control-panel.dark-mode .panel-divider { background: #40444B; }
            #mj-control-panel.dark-mode .panel-section { background: #202225; }
            #mj-control-panel.dark-mode .section-title { color: #DCDDDE; }
            #mj-control-panel.dark-mode label, #mj-control-panel.dark-mode .param-value-display { color: #DCDDDE; }
            #mj-control-panel.dark-mode input[type="text"], #mj-control-panel.dark-mode input[type="number"],
            #mj-control-panel.dark-mode textarea, #mj-control-panel.dark-mode select {
                background: #202225; color: #DCDDDE; border-color: #18191C;
            }
            #mj-control-panel.dark-mode select {
                background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="%23DCDDDE" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>');
            }
            #mj-control-panel.dark-mode input[type="text"]::placeholder, #mj-control-panel.dark-mode input[type="number"]::placeholder,
            #mj-control-panel.dark-mode textarea::placeholder { color: #72767d; opacity: 1; }
            #mj-control-panel.dark-mode input[type="text"].focused, #mj-control-panel.dark-mode input[type="number"].focused,
            #mj-control-panel.dark-mode textarea.focused, #mj-control-panel.dark-mode select.focused { border-color: #7289DA; }
            #mj-control-panel.dark-mode #prompt-params { background:#202225; }
            #mj-control-panel.dark-mode .results-section-divider { border-top-color: #40444B; }

            /* 暗黑模式下的主题触发按钮和菜单 */
            #mj-control-panel.dark-mode .theme-trigger-btn {
                border-color: #2D2F34; background-color: #2B2D31; color: #DCDDDE;
            }
            #mj-control-panel.dark-mode .theme-trigger-btn:hover { border-color: #7289DA; }
            #mj-control-panel.dark-mode .theme-options-menu {
                background-color: #2B2D31; border-color: #202225;
            }
            #mj-control-panel.dark-mode .theme-option-button { color: #DCDDDE; }
            #mj-control-panel.dark-mode .theme-option-button:hover { background-color: #393c43; }
            #mj-control-panel.dark-mode .theme-option-button.active { background-color: #404EED; color: white; }


            /* 比例预览 暗黑 */
            #mj-control-panel.dark-mode .ratio-preview-bg { border-color: #40444B; }
            #mj-control-panel.dark-mode .ratio-box { background: #40444B; color: #DCDDDE; border-color: #70747A; }

            /* 滑块 暗黑 */
            #mj-control-panel.dark-mode input[type="range"]::-webkit-slider-runnable-track { background: #40444B; }
            #mj-control-panel.dark-mode input[type="range"]::-moz-range-track { background: #40444B; }
            #mj-control-panel.dark-mode input[type="range"]::-webkit-slider-thumb { background-color: #7289DA; border-color: #5865F2; }
            #mj-control-panel.dark-mode input[type="range"]::-moz-range-thumb { background-color: #7289DA; border-color: #5865F2; }

            /* 按钮组 暗黑 (通用) */
            #mj-control-panel.dark-mode .btn-group { border-color: #2D2F34; } /* Darker border for the group */
            #mj-control-panel.dark-mode .btn-group button { background: #40444B; color: #DCDDDE; }
            #mj-control-panel.dark-mode .btn-group button:not(:last-child) { border-right-color: #2D2F34; }
            #mj-control-panel.dark-mode .btn-group button.active { background: #5865F2; color: white; }
            /* #mj-control-panel.dark-mode .visibility-btn-group button.active { background: #404EED; color: white; border-color: #404EED; } */ /* No longer needed */


            /* 切换开关 暗黑 */
            #mj-control-panel.dark-mode .toggle-switch { background: #4E4F52; }
            #mj-control-panel.dark-mode .toggle-switch .toggle-dot { background: #B9BBBE; }
            #mj-control-panel.dark-mode .toggle-switch.active { background: #5865F2; }
            #mj-control-panel.dark-mode .toggle-switch.active .toggle-dot { transform: translateX(20px); }

            /* 操作按钮 暗黑 */
            #mj-control-panel.dark-mode .action-button { background:#5865F2; color:white; }
            #mj-control-panel.dark-mode .action-button:hover { background:#4752C4; }
            #mj-control-panel.dark-mode .action-button-primary { background:#5865F2; color:white; border: 1px solid #5865F2;}
            #mj-control-panel.dark-mode .action-button-primary:hover { background:#4752C4; }
            #mj-control-panel.dark-mode .action-button-secondary { background:#40444B; color:#DCDDDE; border: 1px solid #2D2F34; }
            #mj-control-panel.dark-mode .action-button-secondary:hover { background:#4F545C; }
            #mj-control-panel.dark-mode #size-buttons button { background: #40444B; color: #DCDDDE; border-color: #2D2F34; }
            #mj-control-panel.dark-mode #size-buttons button.active { background: #5865F2; color: white; border-color: #5865F2; }
            #mj-control-panel.dark-mode #size-buttons button:hover:not(.active) { background: #4f545c; }


            /* 参考图预览 暗黑 */
            #mj-control-panel.dark-mode .ref-image-preview { border-color: #40444B; }
            #mj-control-panel.dark-mode .ref-image-preview:hover { box-shadow: 0 2px 6px rgba(0,0,0,0.3); }
            #mj-control-panel.dark-mode .ref-image-error { background: #40444B; color: #aaa; border: 1px solid #555; }
            #mj-control-panel.dark-mode .ref-weight-badge { background: rgba(0,0,0,0.7); color: white; border-top-color: #5865F2; border-right-color: #5865F2; }
            #mj-control-panel.dark-mode .ref-delete-btn { background: rgba(239, 68, 68, 0.7); }
            #mj-control-panel.dark-mode .ref-delete-btn:hover { background: rgb(239, 68, 68); }

            #mj-control-panel.dark-mode .ref-code-container { background: #202225; color: #DCDDDE; border-color: #2D2F34; }
            #mj-control-panel.dark-mode .ref-code-weight-badge { background: rgba(88, 101, 242, 0.3); color: #B9BBBE; }
            #mj-control-panel.dark-mode .ref-code-delete-btn { background: rgba(239, 68, 68, 0.3); color: #FAA; }
            #mj-control-panel.dark-mode .ref-code-delete-btn:hover { background: rgba(239, 68, 68, 0.5); }
        `;
        document.head.appendChild(styleSheet);
    }

    // 初始化函数
    function init() {
        injectStyles();
        resetParams(); // 或从存储中加载
        createSettingButton();
        createControlPanel(); // 这也会处理初始主题检测和UI更新
        updatePromptParams();
    }

    const discordAppMount = document.getElementById('app-mount');
    if (discordAppMount) {
        setTimeout(init, 500);
    } else {
        window.addEventListener('load', () => setTimeout(init, 500), { once: true });
    }
})();