Greasy Fork

Greasy Fork is available in English.

Discord Midjourney 参数面板

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Discord Midjourney 参数面板
// @namespace    https://github.com/cwser
// @version      0.2.3
// @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: [],    // 格式: {url, weight}
        sref: [],    // 格式: {url, weight}
        oref: [],    // 格式: {url, weight}
        iref: [],    // This was in the original params but not used in UI or output, kept for consistency if it's planned for future
        directImages: [], // 格式: {url, weight}
        // 新增参数
        tile: false,
        seed: '',
        quality: 1,
        stop: 100,
        visibility: '',
        // 新增个性化参数
        personalParams: '',
        // 新增批量任务参数
        r: 1
    };

    // 显示 Toast 提示
    function showToast(message) {
        const toast = document.createElement('div');
        toast.textContent = message;
        toast.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 10px 16px;
            border-radius: 6px;
            z-index: 99999;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            transform: translateY(-20px);
            opacity: 0;
            transition: all 0.3s ease;
        `;

        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)) { // Check if toast is still in body
                    document.body.removeChild(toast);
                }
            }, 300);
        }, 2000);
    }

    // 创建设置按钮
    function createSettingButton() {
        const button = document.createElement('button');
        button.textContent = 'MJ设置';
        button.style.cssText = `
            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: all 0.2s ease;
        `;

        button.addEventListener('click', toggleControlPanel);
        document.body.appendChild(button);

        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = '#4752C4';
            button.style.transform = 'scale(1.05)';
        });

        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = '#5865F2';
            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 {
                panel.style.opacity = '0';
                panel.style.transform = 'translateY(10px)';
                setTimeout(() => {
                    panel.style.display = 'none';
                }, 200); // Wait for animation to complete before hiding
            }
        }
    }

    // 重置参数
    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, /* iref not used in output */ directImages, tile, seed, quality, stop, visibility, personalParams } = params;

        // 处理其他参数
        const otherParts = [
            `--ar ${ar}`,
            `--s ${stylize}`, // MODIFIED: Always include --s, even if 0
            weird !== 0 ? `--w ${weird}` : '',
            chaos !== 0 ? `--c ${chaos}` : '',
            mode !== 'standard' ? `--${mode}` : '', // Ensure 'standard' is default and not added
            draft ? '--draft' : '',
            noPrompt ? `--no ${noPrompt}` : '',
            version.startsWith('niji') ? `--niji ${version.replace('niji', '')}` : `--v ${version.replace('v', '')}`,
            speed !== 'relax' ? `--${speed}` : '', // Only add speed if not default relax
            tile ? '--tile' : '',
            seed ? `--seed ${seed}` : '',
            quality !== 1 ? `--q ${quality}` : '', // Only add if not default 1
            stop !== 100 ? `--stop ${stop}` : '', // Only add if not default 100
            visibility ? `--${visibility}` : '', // Will be --public or --stealth
            personalParams ? `--p ${personalParams}` : '',
            params.r > 1 ? `--r ${params.r}` : '' // Only add if r > 1
        ];

        // 处理带权重的图像参考
        const formatImageWithWeight = (url, weight, prefix) => {
            let formatted = url;
            if (weight && weight.trim() !== '') { // Check if weight is provided and not empty
                formatted += ` ${prefix} ${weight.trim()}`;
            }
            return formatted;
        };

        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')}`), // MODIFIED: Unified sref handling
                ...oref.map(item => `--oref ${formatImageWithWeight(item.url, item.weight, '--ow')}`),
                ...otherParts.filter(Boolean) // Filter out empty strings
            ].filter(Boolean); // Filter out any completely empty parts

            promptField.value = allParts.join(' ').trim();
        }
    }

    // 创建控制面板
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'mj-control-panel';
        panel.style.cssText = `
            display: none;
            position: fixed;
            right: 20px;
            bottom: 80px; /* Adjusted to make space for settings button */
            width: 1080px;
            max-width: calc(100% - 40px);
            background: white;
            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; /* Added transition for opacity and transform */
            color: #111827;
        `;

        panel.innerHTML = `
            <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:20px;">
                <h3 style="margin:0; color:#111827; font-size:18px; font-weight:600;">Midjourney 参数设置</h3>
                <div style="flex:1; height:1px; background:#e5e7eb; margin:0 16px;"></div>
                <button id="theme-toggle" style="background:none; border:none; cursor:pointer; color:#6B7280; transition: color 0.2s ease; font-size: 16px;">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-moon-stars-fill" 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>
                </button>
            </div>

            <div style="display:grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap:20px;">
                <div style="background:#f9fafb; padding:16px; border-radius:8px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">图片尺寸 (--ar)</p>
                    <div style="display:flex; align-items:center; gap:20px;">
                        <div style="position:relative; width:100px; height:100px;">
                            <div style="position:absolute; top:0; left:0; width:100px; height:100px; border:2px dashed #d1d5db; border-radius:12px;"></div>
                            <div id="ratio-preview" style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:100px; height:100px;">
                                <div style="width:100px; height:100px; border:2px dashed #d1d5db; border-radius:12px; position:absolute; top:0; left:0;"></div>
                                <div id="ratio-box" style="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;">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 style="background:#f9fafb; padding:16px; border-radius:8px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">美学参数</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" 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" 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" style="width:40px; text-align:right;">0</span>
                        </div>
                    </div>
                </div>

                <div style="background:#f9fafb; padding:16px; border-radius:8px; display: flex; flex-direction: column; gap: 10px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">模型设置</p>
                    <div style="display:flex; gap:10px; align-items:center;">
                        <label style="flex:1;">速度
                            <div class="btn-group" style="display:flex; border-radius:6px; overflow:hidden; border:1px solid #d1d5db;">
                                <button data-value="relax" class="speed-btn active" style="flex:1; padding:6px; background:white; border:none; cursor:pointer;">标准</button>
                                <button data-value="fast" class="speed-btn" style="flex:1; padding:6px; background:white; border:none; cursor:pointer;">快速</button>
                                <button data-value="turbo" class="speed-btn" style="flex:1; padding:6px; background:white; border:none; cursor:pointer;">极速</button>
                            </div>
                        </label>
                        <label style="flex:1;">模式
                            <div class="btn-group" style="display:flex; border-radius:6px; overflow:hidden; border:1px solid #d1d5db;">
                                <button data-value="standard" class="mode-btn active" style="flex:1; padding:6px; background:white; border:none; cursor:pointer;">标准</button>
                                <button data-value="raw" class="mode-btn" style="flex:1; padding:6px; background:white; border:none; cursor:pointer;">原始</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" style="position:relative; width:40px; height:20px; border-radius:10px; background:#e5e7eb; cursor:pointer;">
                                <div class="toggle-dot" style="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;"></div>
                            </div>
                        </label>
                        <label for="version-select" style="flex:2;">版本 (--v, --niji)
                            <select id="version-select" name="version-select" style="width:100%; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                                <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 style="background:#f9fafb; padding:16px; border-radius:8px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">角色参考 (--cref)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="cref-url" placeholder="粘贴角色图片URL" style="flex:3; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                        <input type="number" id="cref-weight" placeholder="权重 (--cw)" style="flex:1; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                    </div>
                    <button id="cref-add" style="margin-top:6px; padding:4px 8px; background:#4f46e5; color:white; border:none; border-radius:4px; cursor:pointer; transition:all 0.2s ease;">添加</button>
                    <div id="cref-preview" style="margin-top:10px; display:flex; flex-wrap:wrap; gap:8px;"></div>
                </div>

                <div style="background:#f9fafb; padding:16px; border-radius:8px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">风格参考 (--sref)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="sref-url" placeholder="图片URL, 'random'或数字码" style="flex:3; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                        <input type="number" id="sref-weight" placeholder="权重 (--sw)" style="flex:1; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                    </div>
                    <button id="sref-add" style="margin-top:6px; padding:4px 8px; background:#4f46e5; color:white; border:none; border-radius:4px; cursor:pointer; transition:all 0.2s ease;">添加</button>
                    <div id="sref-preview" style="margin-top:10px; display:flex; flex-wrap:wrap; gap:8px;"></div>
                </div>

                <div style="background:#f9fafb; padding:16px; border-radius:8px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">全方位参考 (--oref)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="oref-url" placeholder="粘贴全方位参考图片URL" style="flex:3; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                        <input type="number" id="oref-weight" placeholder="权重 (--ow)" style="flex:1; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                    </div>
                    <button id="oref-add" style="margin-top:6px; padding:4px 8px; background:#4f46e5; color:white; border:none; border-radius:4px; cursor:pointer; transition:all 0.2s ease;">添加</button>
                    <div id="oref-preview" style="margin-top:10px; display:flex; flex-wrap:wrap; gap:8px;"></div>
                </div>

                <div style="background:#f9fafb; padding:16px; border-radius:8px;">
                    <p style="margin:0 0 8px 0; font-weight:500;">图像参考 (URL --iw)</p>
                    <div style="display:flex; gap:8px; margin-bottom:8px;">
                        <input type="text" id="direct-image-url" placeholder="粘贴图像URL" style="flex:3; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                        <input type="number" id="direct-image-weight" placeholder="权重 (--iw)" style="flex:1; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                    </div>
                    <button id="direct-image-add" style="margin-top:6px; padding:4px 8px; background:#4f46e5; color:white; border:none; border-radius:4px; cursor:pointer; transition:all 0.2s ease;">添加</button>
                    <div id="direct-image-preview" style="margin-top:10px; display:flex; flex-wrap:wrap; gap:8px;"></div>
                </div>

                <div style="background:#f9fafb; padding:16px; border-radius:8px; grid-column: span 2;">
                    <p style="margin:0 0 8px 0; font-weight:500;">更多参数</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" style="position:relative; width:40px; height:20px; border-radius:10px; background:#e5e7eb; cursor:pointer;">
                                    <div class="toggle-dot" style="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;"></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" style="width:120px; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                            </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="输入个性化参数" style="flex:1; padding:6px; border-radius:6px; border:1px solid #d1d5db;">
                            </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.25" max="1" step="0.25" value="1" style="flex:1; margin:0 10px;"> <span id="quality-value">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" style="flex:1; margin:0 10px;">
                                <span id="stop-value">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" style="flex:1; margin:0 10px;">
                                <span id="r-value">1</span>
                            </div>
                        </div>
                    </div>
                    <div style="margin-top:10px;">
                        <p style="margin:0 0 8px 0; font-weight:500;">可见性 (--public, --stealth)</p>
                        <div style="display:flex; gap:10px;">
                            <button data-value="" class="visibility-btn active" style="padding:6px 12px; border:1px solid #d1d5db; border-radius:6px; cursor:pointer; transition:all 0.2s ease;">默认</button>
                            <button data-value="public" class="visibility-btn" style="padding:6px 12px; border:1px solid #d1d5db; border-radius:6px; cursor:pointer; transition:all 0.2s ease;">公开</button>
                            <button data-value="stealth" class="visibility-btn" style="padding:6px 12px; border:1px solid #d1d5db; border-radius:6px; cursor:pointer; transition:all 0.2s ease;">隐身</button>
                        </div>
                    </div>
                </div>
            </div>

            <div style="margin-top:20px; border-top:1px solid #e5e7eb; padding-top:16px;">
                <div style="display:flex; gap:10px;">
                    <div style="flex:1;">
                        <p style="margin:0 0 8px 0; font-weight:500;">提示词</p>
                        <textarea id="main-prompt" placeholder="输入主要提示词..." style="width:100%; height:80px; padding:10px; box-sizing:border-box; border-radius:6px; border:1px solid #d1d5db; transition:border-color 0.2s ease;"></textarea>
                    </div>
                    <div style="flex:1;">
                        <p style="margin:0 0 8px 0; font-weight:500;">排除词 (--no)</p>
                        <textarea id="no-prompt" placeholder="输入需要排除的元素,多个用空格分隔" style="width:100%; height:80px; padding:10px; box-sizing:border-box; border-radius:6px; border:1px solid #d1d5db; transition:border-color 0.2s ease;"></textarea>
                    </div>
                    <div style="flex:1;">
                        <p style="margin:0 0 8px 0; font-weight:500;">最终参数</p>
                        <textarea id="prompt-params" style="width:100%; height:80px; padding:10px; background:#f9fafb; border-radius:6px; border:1px solid #d1d5db; transition:border-color 0.2s ease; cursor:pointer;" readonly></textarea>
                    </div>
                </div>
            </div>

            <div style="margin-top:16px; display:flex; gap:10px;">
                <button id="copy-btn" style="flex:1; padding:8px; background:#4f46e5; color:white; border:none; border-radius:6px; cursor:pointer; transition:all 0.2s ease;">拷贝参数</button>
                <button id="clear-btn" style="flex:1; padding:8px; background:#e5e7eb; color:#111827; border:none; border-radius:6px; cursor:pointer; transition:all 0.2s ease;">清空参数</button>
            </div>
        `;

        document.body.appendChild(panel);
        bindControlEvents(); // Bind events after appending
    }

    function setInitialActiveButtons() {
        const buttonGroups = [
            { className: 'speed-btn', param: 'speed', defaultValue: 'relax' },
            { className: 'mode-btn', param: 'mode', defaultValue: 'standard' },
            { className: 'visibility-btn', param: 'visibility', defaultValue: '' }
        ];

        buttonGroups.forEach(group => {
            const buttons = document.querySelectorAll(`.${group.className}`);
            let currentParamValue = params[group.param] === undefined ? group.defaultValue : params[group.param];

            buttons.forEach(btn => {
                if (btn.dataset.value === currentParamValue) {
                    btn.classList.add('active');
                    btn.style.backgroundColor = '#4f46e5';
                    btn.style.color = 'white';
                } else {
                    btn.classList.remove('active');
                    btn.style.backgroundColor = 'white';
                    btn.style.color = '#111827';
                }
            });
        });
    }


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

        let isDarkMode = false;
        const themeToggleButton = $('theme-toggle');
        const sunIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-brightness-high-fill" 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 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 0a.5.5 0 0 1-.707.707l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707.707L2.343 3.757a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707z"/></svg>`;
        const moonIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-moon-stars-fill" 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>`;

        themeToggleButton.addEventListener('click', () => {
            isDarkMode = !isDarkMode;
            const panel = $('mj-control-panel');
            const allButtons = panel.querySelectorAll('button'); // More specific selection if needed
            const inputsAndTextareas = panel.querySelectorAll('input, textarea, select');
            const bgElements = panel.querySelectorAll('[style*="background:#f9fafb"], .btn-group');
            const labels = panel.querySelectorAll('label, p, h3, span');


            if (isDarkMode) {
                panel.style.backgroundColor = '#2B2D31'; // Discord dark theme background
                panel.style.color = '#DCDDDE';         // Discord dark theme text
                panel.style.borderColor = '#202225';   // Discord dark theme border

                labels.forEach(label => label.style.color = '#DCDDDE');
                themeToggleButton.innerHTML = sunIcon;
                themeToggleButton.style.color = '#DCDDDE';


                allButtons.forEach(btn => {
                     if (!btn.classList.contains('active') && !btn.id.startsWith('theme-toggle')) { // Keep active button styles
                        btn.style.backgroundColor = '#40444B'; // Discord button dark
                        btn.style.color = '#DCDDDE';
                        btn.style.borderColor = '#2D2F34'; // Slightly darker border for buttons
                    } else if (btn.classList.contains('active')) {
                        btn.style.backgroundColor = '#5865F2'; // Keep active color
                        btn.style.color = 'white';
                    }
                });

                inputsAndTextareas.forEach(input => {
                    input.style.backgroundColor = '#202225'; // Discord input dark
                    input.style.color = '#DCDDDE';
                    input.style.borderColor = '#18191C'; // Discord input border dark
                    if (input.type === 'range') {
                         input.style.setProperty('--thumb-bg', '#DCDDDE');
                         input.style.setProperty('--track-bg', '#40444B');
                    }
                });
                bgElements.forEach(el => el.style.backgroundColor = '#202225'); // Card backgrounds

                // Update ratio box for dark mode
                const ratioBox = $('ratio-box');
                if (ratioBox) {
                    ratioBox.style.background = '#40444B';
                    ratioBox.style.color = '#DCDDDE';
                    ratioBox.style.borderColor = '#DCDDDE';
                }


            } else { // Light Mode
                panel.style.backgroundColor = 'white';
                panel.style.color = '#111827';
                panel.style.borderColor = '#E5E7EB';

                labels.forEach(label => label.style.color = '#111827'); // Reset label colors
                themeToggleButton.innerHTML = moonIcon;
                themeToggleButton.style.color = '#6B7280';


                allButtons.forEach(btn => {
                    if (!btn.classList.contains('active') && !btn.id.startsWith('theme-toggle')) {
                        btn.style.backgroundColor = 'white'; // Default light mode button
                        btn.style.color = '#111827';
                        btn.style.borderColor = '#d1d5db';
                    } else if (btn.classList.contains('active')) {
                        btn.style.backgroundColor = '#4f46e5'; // Active color for light
                        btn.style.color = 'white';
                    }
                 });


                inputsAndTextareas.forEach(input => {
                    input.style.backgroundColor = 'white';
                    input.style.color = '#111827';
                    input.style.borderColor = '#d1d5db';
                     if (input.type === 'range') {
                         input.style.removeProperty('--thumb-bg');
                         input.style.removeProperty('--track-bg');
                    }
                });
                 bgElements.forEach(el => {
                    if(el.classList.contains('btn-group')) {
                        el.style.backgroundColor = 'transparent'; // Or specific light mode for btn-group
                    } else {
                        el.style.backgroundColor = '#f9fafb';
                    }
                });

                // Reset ratio box for light mode
                const ratioBox = $('ratio-box');
                if (ratioBox) {
                    ratioBox.style.background = '#f3f4f6';
                    ratioBox.style.color = '#374151';
                    ratioBox.style.borderColor = '#374151';
                }
            }
            setInitialActiveButtons(); // Re-apply active button styles to ensure they are correct after theme change
        });


        $('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; // Display the raw value from slider for precision
                updatePromptParams();
            };
        };

        bindSliderEvent('stylize', 'stylize', 'stylize-value');
        bindSliderEvent('weird', 'weird', 'weird-value');
        bindSliderEvent('chaos', 'chaos', 'chaos-value');
        bindSliderEvent('quality-slider', 'quality', 'quality-value', true); // Quality can be float
        bindSliderEvent('stop-slider', 'stop', 'stop-value');
        bindSliderEvent('r-slider', 'r', 'r-value');


        const bindRadioGroup = (groupClass, property, defaultValue) => {
            document.querySelectorAll(`.${groupClass}`).forEach(btn => {
                btn.addEventListener('click', () => {
                    document.querySelectorAll(`.${groupClass}`).forEach(b => {
                        b.classList.remove('active');
                        b.style.backgroundColor = isDarkMode ? '#40444B' : 'white';
                        b.style.color = isDarkMode ? '#DCDDDE' : '#111827';
                    });
                    btn.classList.add('active');
                    btn.style.backgroundColor = isDarkMode ? '#5865F2' : '#4f46e5'; // Use theme-appropriate active color
                    btn.style.color = 'white';
                    params[property] = btn.dataset.value;
                    updatePromptParams();
                });
            });
        };

        bindRadioGroup('speed-btn', 'speed', 'relax');
        bindRadioGroup('mode-btn', 'mode', 'standard');
        bindRadioGroup('visibility-btn', 'visibility', '');


        const bindToggleSwitch = (switchId, property) => {
            const switchEl = $(switchId);
            if (!switchEl) return;
            const dot = switchEl.querySelector('.toggle-dot');
            if (!dot) return;

            // Set initial state
            if (params[property]) {
                dot.style.transform = 'translateX(20px)';
                switchEl.style.backgroundColor = isDarkMode ? '#5865F2' : '#4f46e5';
            } else {
                dot.style.transform = 'translateX(0)';
                switchEl.style.backgroundColor = isDarkMode ? '#4E4F52' : '#e5e7eb';
            }

            switchEl.addEventListener('click', () => {
                params[property] = !params[property];
                if (params[property]) {
                    dot.style.transform = 'translateX(20px)';
                    switchEl.style.backgroundColor = isDarkMode ? '#5865F2' : '#4f46e5';
                } else {
                    dot.style.transform = 'translateX(0)';
                    switchEl.style.backgroundColor = isDarkMode ? '#4E4F52' : '#e5e7eb';
                }
                updatePromptParams();
            });
        };

        bindToggleSwitch('tile-toggle-switch', 'tile');
        bindToggleSwitch('draft-toggle-switch', 'draft'); // Corrected ID for draft toggle

        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) return;
                textarea.select();
                try {
                    document.execCommand('copy');
                    showToast('参数已复制!');
                } catch (err) {
                    showToast('复制失败!');
                    console.error('Copy failed:', err);
                }
            };
        }

        if ($('clear-btn')) {
            $('clear-btn').onclick = () => {
                resetParams(); // Resets the params object

                // Reset UI elements
                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; // Default to 1:1 if not found
                    $('ratio-slider').dispatchEvent(new Event('input')); // Trigger update
                }

                ['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')) $('quality-slider').value = params.quality;
                if ($('quality-value')) $('quality-value').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;

                // Reset Toggles by re-running their bind function or manually setting them
                bindToggleSwitch('tile-toggle-switch', 'tile');
                bindToggleSwitch('draft-toggle-switch', 'draft');


                setInitialActiveButtons(); // This will correctly set active states for radio buttons
                refreshPreviews();
                updatePromptParams(); // Update the final parameter string
                showToast('所有参数已重置为默认值');
            };
        }


        const setupRefSection = (type) => {
            const addBtn = $(`${type}-add`);
            const urlInput = $(`${type}-url`);
            const weightInput = $(`${type}-weight`);
            const previewContainerId = `${type}-preview`;

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

            addBtn.onclick = () => {
                const url = urlInput.value.trim();
                const weight = weightInput.value.trim();

                if (!url) {
                    showToast(`请输入${type === 'sref' ? 'URL或代码' : 'URL'}`);
                    return;
                }

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

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

                const targetArray = params[type === 'directImages' ? 'directImages' : type];
                const srefCodeToAdd = isSrefCode ? (url.toLowerCase() === 'random' ? 'random' : url) : url;
                const itemUrl = type === 'sref' ? srefCodeToAdd : url;


                if (!targetArray.some(item => item.url === itemUrl)) {
                    targetArray.push({ url: itemUrl, weight });
                    if (isSrefCode) {
                        addPreviewSrefCode(previewContainerId, itemUrl, weight);
                    } else {
                         const weightPrefix = {'cref': '--cw', 'sref': '--sw', 'oref': '--ow', 'directImages': '--iw'}[type];
                        addPreviewImage(previewContainerId, itemUrl, weight, type, weightPrefix);
                    }
                    urlInput.value = '';
                    weightInput.value = '';
                    updatePromptParams();
                } else {
                    showToast(`该${type === 'sref' && isSrefCode ? '码' : 'URL'}已添加`);
                }
            };
        };

        setupRefSection('cref');
        setupRefSection('sref');
        setupRefSection('oref');
        setupRefSection('directImages');


        const sizeMap = ['1:2', '9:16', '2:3', '3:4', '5:6', '1:1', '6:5', '4:3', '3:2', '16:9', '2:1'];
        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;
                }

                const presetMap = { '纵向': '1:2', '正方形': '1:1', '横向': '2:1' };
                document.querySelectorAll('#size-buttons button').forEach(btn => {
                    const btnRatio = presetMap[btn.textContent];
                    if (btnRatio === ratio) {
                        btn.classList.add('active');
                        btn.style.backgroundColor = isDarkMode ? '#5865F2' :'#4f46e5';
                        btn.style.color = 'white';
                    } else {
                        btn.classList.remove('active');
                        btn.style.backgroundColor = isDarkMode ? '#40444B' : 'white';
                        btn.style.color = isDarkMode ? '#DCDDDE' : '#111827';
                    }
                });
                updatePromptParams();
            };
            // Initial trigger for ratio slider to set preview
            const initialRatioIndex = sizeMap.indexOf(params.ar);
            ratioSlider.value = initialRatioIndex !== -1 ? initialRatioIndex : 5; // Default to 1:1
            ratioSlider.dispatchEvent(new Event('input'));
        }


        const btnGroup = $('size-buttons');
        if (btnGroup) {
            const presetMap = { '纵向': '1:2', '正方形': '1:1', '横向': '2:1' };
            ['纵向', '正方形', '横向'].forEach((label, i) => {
                const btn = document.createElement('button');
                btn.textContent = label;
                btn.dataset.value = presetMap[label];
                btn.style.cssText = 'padding:4px 12px; border-radius:6px; border:1px solid #d1d5db; background:white; cursor:pointer; transition:all 0.2s ease;';
                if ((isDarkMode && params.ar === presetMap[label]) || (!isDarkMode && params.ar === presetMap[label]) ) {
                     btn.classList.add('active');
                     btn.style.backgroundColor = isDarkMode ? '#5865F2' : '#4f46e5';
                     btn.style.color = 'white';
                } else if (params.ar === presetMap[label]) { // Default active for 1:1 (正方形)
                    btn.classList.add('active');
                    btn.style.backgroundColor = '#4f46e5';
                    btn.style.color = 'white';
                }


                btn.onclick = () => {
                    const ratio = presetMap[label];
                    const sliderIndex = sizeMap.indexOf(ratio);
                    if (sliderIndex !== -1 && ratioSlider) {
                        ratioSlider.value = sliderIndex;
                        ratioSlider.dispatchEvent(new Event('input'));
                    }
                };
                btnGroup.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', () => {
                promptParamsTextarea.select();
                 try {
                    document.execCommand('copy');
                    showToast('参数已复制!');
                } catch (err) {
                    showToast('复制失败!');
                    console.error('Copy failed:', err);
                }
            });
        }


        document.querySelectorAll('input, textarea, select').forEach(el => {
            el.addEventListener('focus', () => {
                el.style.borderColor = isDarkMode ? '#7289DA' : '#4f46e5'; // Discord focus color for dark, app purple for light
            });
            el.addEventListener('blur', () => {
                el.style.borderColor = isDarkMode ? '#202225' : '#d1d5db';
            });
        });

        document.querySelectorAll('button').forEach(btn => {
            const originalBg = btn.style.backgroundColor;
            const originalTransform = btn.style.transform;
            const originalShadow = btn.style.boxShadow;

            btn.addEventListener('mouseenter', () => {
                if (!btn.classList.contains('active') && !btn.id.startsWith('theme-toggle')) {
                    btn.style.transform = 'translateY(-1px)';
                    btn.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
                    if (isDarkMode) btn.style.backgroundColor = '#4F545C'; // Slightly lighter for hover in dark
                    // else btn.style.filter = 'brightness(0.95)'; // Keep for light if needed
                }
            });
            btn.addEventListener('mouseleave', () => {
                 if (!btn.classList.contains('active')) {
                    btn.style.transform = originalTransform || 'translateY(0)';
                    btn.style.boxShadow = originalShadow || 'none';
                    if (isDarkMode) btn.style.backgroundColor = '#40444B'; // Back to normal dark button
                    // else btn.style.filter = 'none';
                 }
            });
        });
    }

    function addPreviewImage(containerId, url, weight, paramType, weightPrefix) {
        const container = document.getElementById(containerId);
        if (!container) return;
        const imgContainer = document.createElement('div');
        imgContainer.style.cssText = 'position: relative; margin: 4px; animation: fadeIn 0.3s ease;';

        const img = document.createElement('img');
        img.src = url;
        img.style.width = '60px';
        img.style.height = '60px';
        img.style.objectFit = 'cover';
        img.style.borderRadius = '4px';
        img.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
        img.style.transition = 'all 0.2s ease';
        img.onerror = () => { // Handle broken image links
            imgContainer.innerHTML = `<div style="width:60px; height:60px; background:#eee; color:#999; display:flex; align-items:center; justify-content:center; border-radius:4px; font-size:10px; text-align:center;">无效图片</div>`;
        };


        img.addEventListener('mouseenter', () => { img.style.transform = 'scale(1.05)'; img.style.boxShadow = '0 4px 8px rgba(0,0,0,0.15)'; });
        img.addEventListener('mouseleave', () => { img.style.transform = 'scale(1)'; img.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)'; });

        const weightBadge = document.createElement('div');
        weightBadge.style.cssText = 'position: absolute; bottom: 0; left: 0; background: rgba(0,0,0,0.7); color: white; font-size: 10px; padding: 1px 3px; border-radius: 0 4px 0 0;';
        const wP = weightPrefix ? weightPrefix.replace('--', '') : '';
        weightBadge.textContent = weight && weight.trim() !== '' ? `${wP}:${weight}` : `${wP}:默认`;


        const deleteBtn = document.createElement('button');
        deleteBtn.style.cssText = 'position: absolute; top: -4px; right: -4px; background: rgba(239, 68, 68, 0.9); color: white; border: none; border-radius: 50%; width: 16px; height: 16px; font-size: 10px; line-height: 16px; text-align:center; cursor:pointer; transition:all 0.2s ease; opacity: 0.8; display:flex; align-items:center; justify-content:center;';
        deleteBtn.innerHTML = '&times;';
        deleteBtn.onclick = function(e) {
            e.stopPropagation();
            imgContainer.style.animation = 'fadeOut 0.2s ease forwards';
            setTimeout(() => {
                const targetArray = params[paramType === 'directImages' ? 'directImages' : paramType];
                const index = targetArray.findIndex(item => item.url === url);
                if (index !== -1) {
                    targetArray.splice(index, 1);
                    if (container.contains(imgContainer)) container.removeChild(imgContainer);
                    updatePromptParams();
                }
            }, 200);
        };
        deleteBtn.addEventListener('mouseenter', () => { deleteBtn.style.opacity = '1'; deleteBtn.style.transform = 'scale(1.1)'; });
        deleteBtn.addEventListener('mouseleave', () => { deleteBtn.style.opacity = '0.8'; deleteBtn.style.transform = 'scale(1)'; });

        imgContainer.appendChild(img);
        imgContainer.appendChild(weightBadge);
        imgContainer.appendChild(deleteBtn);
        container.appendChild(imgContainer);
    }

    function addPreviewSrefCode(containerId, code, weight) {
        const container = document.getElementById(containerId);
        if (!container) return;
        const codeContainer = document.createElement('div');
        codeContainer.style.cssText = 'position: relative; margin: 4px; background: #f3f4f6; border-radius: 4px; padding: 6px 10px; display: flex; align-items: center; font-family: monospace; font-size: 12px; color: #111827; animation: fadeIn 0.3s ease;';
        if (document.getElementById('mj-control-panel').style.backgroundColor === 'rgb(43, 45, 49)') { // Check for dark mode
             codeContainer.style.background = '#202225';
             codeContainer.style.color = '#DCDDDE';
        }


        const codeText = document.createElement('span');
        codeText.textContent = `sref:${code}`;

        const weightBadge = document.createElement('div');
        weightBadge.style.cssText = 'margin-left: 8px; background: rgba(79, 70, 229, 0.1); color: #4f46e5; font-size: 10px; padding: 2px 4px; border-radius: 3px;';
        weightBadge.textContent = weight && weight.trim() !== '' ? `sw:${weight}` : 'sw:默认';
        if (document.getElementById('mj-control-panel').style.backgroundColor === 'rgb(43, 45, 49)') { // Dark mode
            weightBadge.style.background = 'rgba(88, 101, 242, 0.3)';
            weightBadge.style.color = '#B9BBBE';
        }


        const deleteBtn = document.createElement('button');
        deleteBtn.style.cssText = 'margin-left: 10px; background: rgba(239, 68, 68, 0.1); color: #ef4444; border: none; border-radius: 4px; padding: 2px 5px; font-size: 10px; line-height:1; cursor:pointer; transition:all 0.2s ease;';
        deleteBtn.innerHTML = '&times;';
        if (document.getElementById('mj-control-panel').style.backgroundColor === 'rgb(43, 45, 49)') { // Dark mode
            deleteBtn.style.background = 'rgba(239, 68, 68, 0.3)';
            deleteBtn.style.color = '#FAA';
        }

        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);
        };
        deleteBtn.addEventListener('mouseenter', () => { deleteBtn.style.backgroundColor = 'rgba(239, 68, 68, 0.2)'; });
        deleteBtn.addEventListener('mouseleave', () => { deleteBtn.style.backgroundColor = 'rgba(239, 68, 68, 0.1)'; });
        if (document.getElementById('mj-control-panel').style.backgroundColor === 'rgb(43, 45, 49)') { // Dark mode hover
            deleteBtn.addEventListener('mouseenter', () => { deleteBtn.style.backgroundColor = 'rgba(239, 68, 68, 0.4)'; });
            deleteBtn.addEventListener('mouseleave', () => { deleteBtn.style.backgroundColor = 'rgba(239, 68, 68, 0.3)'; });
        }


        codeContainer.appendChild(codeText);
        codeContainer.appendChild(weightBadge);
        codeContainer.appendChild(deleteBtn);
        container.appendChild(codeContainer);
    }


    function refreshPreviews() {
        const refTypes = [
            { type: 'cref', previewId: 'cref-preview', weightPrefix: '--cw' },
            { type: 'sref', previewId: 'sref-preview', weightPrefix: '--sw' },
            { type: 'oref', previewId: 'oref-preview', weightPrefix: '--ow' },
            { type: 'directImages', previewId: 'direct-image-preview', weightPrefix: '--iw' }
        ];

        refTypes.forEach(ref => {
            const container = document.getElementById(ref.previewId);
            if (!container) return;
            container.innerHTML = ''; // Clear existing previews

            const items = params[ref.type];
            if (items && Array.isArray(items)) {
                items.forEach(item => {
                    if (ref.type === 'sref' && (item.url === 'random' || /^\d+$/.test(item.url))) {
                        addPreviewSrefCode(ref.previewId, item.url, item.weight);
                    } else {
                        addPreviewImage(ref.previewId, item.url, item.weight, ref.type, ref.weightPrefix);
                    }
                });
            }
        });
    }

    // Inject FontAwesome and some CSS for animations
    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); } }
            input[type="range"] { -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer; width: 100%;}
            input[type="range"]::-webkit-slider-runnable-track { background: #e5e7eb; height: 0.4rem; border-radius: 0.2rem; }
            input[type="range"]::-moz-range-track { background: #e5e7eb; height: 0.4rem; border-radius: 0.2rem; }
            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;}
            input[type="range"]::-moz-range-thumb { border: none; border-radius: 50%; background-color: #4f46e5; height: 1rem; width: 1rem; border: 1px solid #3730a3;}
        `;
        document.head.appendChild(styleSheet);

        const faLink = document.createElement('link');
        faLink.rel = 'stylesheet';
        faLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css'; // Using a common CDN
        document.head.appendChild(faLink);
    }


    function init() {
        injectStyles();
        resetParams();
        createSettingButton(); // Creates the main button
        createControlPanel(); // Creates the panel (initially hidden)
        setInitialActiveButtons(); // Sets default active states for buttons
        updatePromptParams(); // Calculate initial prompt string
    }

    // Check if the script is running in a context where `window` is available
    if (typeof unsafeWindow !== 'undefined') {
        unsafeWindow.addEventListener('load', init);
    } else {
        window.addEventListener('load', init);
    }

})();