Greasy Fork

Greasy Fork is available in English.

Discord Midjourney 参数面板

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

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

// ==UserScript==
// @name         Discord Midjourney 参数面板
// @namespace    https://github.com/cwser
// @version      0.2.4
// @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, 权重}
        sref: [],    // 格式: {url, 权重}
        oref: [],    // 格式: {url, 权重}
        iref: [],    // 这个参数在原始定义中存在,但未在UI或输出中使用,为保持一致性(如果未来计划使用)而保留
        directImages: [], // 格式: {url, 权重}
        // 新增参数
        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)) { // 检查 toast 是否仍在 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); // 等待动画完成后再隐藏
            }
        }
    }

    // 重置参数
    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 未在输出中使用 */ directImages, tile, seed, quality, stop, visibility, personalParams } = params;

        // 处理其他参数
        const otherParts = [
            `--ar ${ar}`,
            `--s ${stylize}`, // 修改:始终包含 --s,即使为 0
            weird !== 0 ? `--w ${weird}` : '',
            chaos !== 0 ? `--c ${chaos}` : '',
            mode !== 'standard' ? `--${mode}` : '', // 确保 'standard' 是默认值且不被添加
            draft ? '--draft' : '',
            noPrompt ? `--no ${noPrompt}` : '',
            version.startsWith('niji') ? `--niji ${version.replace('niji', '')}` : `--v ${version.replace('v', '')}`,
            speed !== 'relax' ? `--${speed}` : '', // 仅在速度不是默认的 relax 时添加
            tile ? '--tile' : '',
            seed ? `--seed ${seed}` : '',
            quality !== 1 ? `--q ${quality}` : '', // 仅在不是默认值 1 时添加
            stop !== 100 ? `--stop ${stop}` : '', // 仅在不是默认值 100 时添加
            visibility ? `--${visibility}` : '', // 将会是 --public 或 --stealth
            personalParams ? `--p ${personalParams}` : '',
            params.r > 1 ? `--r ${params.r}` : '' // 仅在 r > 1 时添加
        ];

        // 处理带权重的图像参考
        const formatImageWithWeight = (url, weight, prefix) => {
            let formatted = url;
            if (weight && weight.trim() !== '') { // 检查是否提供了权重且不为空
                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')}`), // 修改:统一 sref 处理
                ...oref.map(item => `--oref ${formatImageWithWeight(item.url, item.weight, '--ow')}`),
                ...otherParts.filter(Boolean) // 过滤掉空字符串
            ].filter(Boolean); // 过滤掉任何完全为空的部分

            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; /* 已调整,为设置按钮留出空间 */
            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; /* 为不透明度和变换添加了过渡效果 */
            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(); // 添加到DOM后绑定事件
    }

    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'); // 如果需要,进行更具体的选择
            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 暗色主题背景
                panel.style.color = '#DCDDDE';         // Discord 暗色主题文本
                panel.style.borderColor = '#202225';   // Discord 暗色主题边框

                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')) { // 保留激活按钮的样式
                        btn.style.backgroundColor = '#40444B'; // Discord 暗色按钮
                        btn.style.color = '#DCDDDE';
                        btn.style.borderColor = '#2D2F34'; // 按钮使用稍暗的边框
                    } else if (btn.classList.contains('active')) {
                        btn.style.backgroundColor = '#5865F2'; // 保留激活状态颜色
                        btn.style.color = 'white';
                    }
                });

                inputsAndTextareas.forEach(input => {
                    input.style.backgroundColor = '#202225'; // Discord 暗色输入框
                    input.style.color = '#DCDDDE';
                    input.style.borderColor = '#18191C'; // Discord 暗色输入框边框
                    if (input.type === 'range') {
                         input.style.setProperty('--thumb-bg', '#DCDDDE');
                         input.style.setProperty('--track-bg', '#40444B');
                    }
                });
                bgElements.forEach(el => el.style.backgroundColor = '#202225'); // 卡片背景

                // 为暗色模式更新比例框样式
                const ratioBox = $('ratio-box');
                if (ratioBox) {
                    ratioBox.style.background = '#40444B';
                    ratioBox.style.color = '#DCDDDE';
                    ratioBox.style.borderColor = '#DCDDDE';
                }


            } else { // 亮色模式
                panel.style.backgroundColor = 'white';
                panel.style.color = '#111827';
                panel.style.borderColor = '#E5E7EB';

                labels.forEach(label => label.style.color = '#111827'); // 重置标签颜色
                themeToggleButton.innerHTML = moonIcon;
                themeToggleButton.style.color = '#6B7280';


                allButtons.forEach(btn => {
                    if (!btn.classList.contains('active') && !btn.id.startsWith('theme-toggle')) {
                        btn.style.backgroundColor = 'white'; // 默认亮色模式按钮
                        btn.style.color = '#111827';
                        btn.style.borderColor = '#d1d5db';
                    } else if (btn.classList.contains('active')) {
                        btn.style.backgroundColor = '#4f46e5'; // 亮色模式下的激活颜色
                        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'; // 或者为按钮组指定特定的亮色模式
                    } else {
                        el.style.backgroundColor = '#f9fafb';
                    }
                });

                // 为亮色模式重置比例框样式
                const ratioBox = $('ratio-box');
                if (ratioBox) {
                    ratioBox.style.background = '#f3f4f6';
                    ratioBox.style.color = '#374151';
                    ratioBox.style.borderColor = '#374151';
                }
            }
            setInitialActiveButtons(); // 重新应用激活按钮样式以确保在主题更改后它们是正确的
        });


        $('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('quality-slider', 'quality', 'quality-value', true); // 质量可以是浮点数
        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'; // 使用适合主题的激活颜色
                    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;

            // 设置初始状态
            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'); // 已修正的草稿切换开关ID

        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(); // 重置参数对象

                // 重置UI元素
                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; // 如果未找到,则默认为 1:1
                    $('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')) $('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;

                // 通过重新运行其绑定函数或手动设置来重置切换开关
                bindToggleSwitch('tile-toggle-switch', 'tile');
                bindToggleSwitch('draft-toggle-switch', 'draft');


                setInitialActiveButtons(); // 这将正确设置单选按钮的激活状态
                refreshPreviews();
                updatePromptParams(); // 更新最终的参数字符串
                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();
            };
            // 触发比例滑块的初始事件以设置预览
            const initialRatioIndex = sizeMap.indexOf(params.ar);
            ratioSlider.value = initialRatioIndex !== -1 ? initialRatioIndex : 5; // 默认为 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]) { // 默认激活 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 焦点颜色,亮色模式下的应用紫色
            });
            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'; // 暗色模式下悬停时略微变亮
                    // else btn.style.filter = 'brightness(0.95)'; // 如果需要,为亮色模式保留
                }
            });
            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'; // 返回正常的暗色按钮
                    // 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 = () => { // 处理损坏的图片链接
            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)') { // 检查是否为暗色模式
             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)') { // 暗色模式
            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)') { // 暗色模式
            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)') { // 暗色模式悬停
            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 = ''; // 清除现有预览

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

    // 注入 FontAwesome 和一些用于动画的 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); } }
            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'; // 使用一个通用的 CDN
        document.head.appendChild(faLink);
    }


    function init() {
        injectStyles();       // 注入样式
        resetParams();        // 重置参数状态
        createSettingButton(); // 创建主按钮
        createControlPanel();  // 创建面板(初始隐藏)
        setInitialActiveButtons(); // 设置按钮的默认激活状态
        updatePromptParams();      // 计算初始提示字符串
    }

    // 脚本加载后立即初始化
    init();

})();