Greasy Fork

Greasy Fork is available in English.

Discord Midjourney 参数面板

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Discord Midjourney 参数面板
// @namespace    https://github.com/cwser
// @version      0.2.6
// @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, // 默认质量为 1
        stop: 100,
        visibility: '',
        // 新增个性化参数
        personalParams: '',
        // 新增批量任务参数
        r: 1
    };
let isDarkMode = false; // Moved isDarkMode to a higher scope
// 定义 weightPrefixes 映射
    const weightPrefixes = {
        'cref': '--cw',
        'sref': '--sw',
        'oref': '--ow',
        'directImages': '--iw'
    };
// 显示 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, // 默认质量重置为 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}`,
            weird !== 0 ? `--w ${weird}` : '',
            chaos !== 0 ? `--c ${chaos}` : '',
            mode !== 'standard' ? `--${mode}` : '',
            draft ? '--draft' : '',
            noPrompt ? `--no ${noPrompt}` : '',
            version.startsWith('niji') ? `--niji ${version.replace('niji', '')}` : `--v ${version.replace('v', '')}`,
            speed !== 'relax' ? `--${speed}` : '',
            tile ? '--tile' : '',
            seed ? `--seed ${seed}` : '',
            quality !== 1 ? `--q ${quality}` : '', // 仅在不是默认值 1 时添加
            stop !== 100 ? `--stop ${stop}` : '',
            visibility ? `--${visibility}` : '',
            personalParams ? `--p ${personalParams}` : '',
            params.r > 1 ? `--r ${params.r}` : ''
        ];
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')}`),
                ...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" max="4" step="1" value="2" 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 = isDarkMode ? '#5865F2' : '#4f46e5'; // Adjusted for dark mode
                    btn.style.color = 'white';
                } else {
                    btn.classList.remove('active');
                    btn.style.backgroundColor = isDarkMode ? '#40444B' : 'white'; // Adjusted for dark mode
                    btn.style.color = isDarkMode ? '#DCDDDE' : '#111827'; // Adjusted for dark mode
                }
            });
        });
    }
// NEW function: Update visuals for toggle switches
    function updateToggleVisuals(switchId, property) {
        const switchEl = document.getElementById(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)';
            // Use a slightly different off-color for dark mode if desired, or keep consistent
            switchEl.style.backgroundColor = isDarkMode ? '#4E4F52' : '#e5e7eb';
        }
    }
// 修改 setupRefSection 函数
    const setupRefSection = (idPrefix, paramKey) => { // idPrefix 用于HTML ID, paramKey 用于 params 对象
        const $ = id => document.getElementById(id);
        const addBtn = $(`${idPrefix}-add`);
        const urlInput = $(`${idPrefix}-url`);
        const weightInput = $(`${idPrefix}-weight`);
        const previewContainerId = `${idPrefix}-preview`;
if (!addBtn || !urlInput || !weightInput) {
             // console.error(`Setup failed for ${idPrefix}: missing elements. Make sure IDs in HTML match: ${idPrefix}-add, ${idPrefix}-url, ${idPrefix}-weight`);
            return;
        }
addBtn.onclick = () => {
            const url = urlInput.value.trim();
            const weight = weightInput.value.trim();
let toastMessage = `请输入${paramKey === 'sref' ? 'URL或代码' : 'URL'}`;
            if (!url) {
                showToast(toastMessage);
                return;
            }
const isImageUrl = /^https?:\/\/.+\.(jpg|jpeg|png|webp|gif|svg|bmp|tiff|ico)(\?.*)?$/i.test(url);
            const isSrefCode = paramKey === 'sref' && (/^\d+$/.test(url) || url.toLowerCase() === 'random');
if (paramKey !== 'sref' && !isImageUrl) {
                showToast('请输入有效的图片URL');
                return;
            }
            if (paramKey === 'sref' && !isImageUrl && !isSrefCode) {
                showToast("请输入有效图片URL, 'random'或数字sref码");
                return;
            }
const targetArray = params[paramKey]; // 使用 paramKey 访问 params
            if (!Array.isArray(targetArray)) {
                // console.error(`params.${paramKey} is not an array.`);
                return;
            }
const itemUrl = (paramKey === 'sref' && isSrefCode) ? (url.toLowerCase() === 'random' ? 'random' : url) : url;
if (!targetArray.some(item => item.url === itemUrl)) {
                targetArray.push({ url: itemUrl, weight });
                const currentWeightPrefix = weightPrefixes[paramKey]; // 使用 paramKey 获取 weightPrefix
if (paramKey === 'sref' && isSrefCode) { // 明确检查 paramKey 和 isSrefCode
                    addPreviewSrefCode(previewContainerId, itemUrl, weight);
                } else {
                    addPreviewImage(previewContainerId, itemUrl, weight, paramKey, currentWeightPrefix); // 传递 paramKey
                }
                urlInput.value = '';
                weightInput.value = '';
                updatePromptParams();
            } else {
                showToast(`该${(paramKey === 'sref' && isSrefCode) ? '码' : 'URL'}已添加`);
            }
        };
    };
// 绑定控制面板事件
    function bindControlEvents() {
        const $ = id => document.getElementById(id);
// isDarkMode is now at a higher scope
        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';
                panel.style.color = '#DCDDDE';
                panel.style.borderColor = '#202225';
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';
                        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';
                    input.style.color = '#DCDDDE';
                    input.style.borderColor = '#18191C';
                    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(); // Refresh button active states according to theme
            updateToggleVisuals('tile-toggle-switch', 'tile'); // Update toggle visuals for theme
            updateToggleVisuals('draft-toggle-switch', 'draft'); // Update toggle visuals for theme
            refreshPreviews(); // To update sref code block colors if needed
        });
$('main-prompt').oninput = e => { params.prompt = e.target.value; updatePromptParams(); };
const bindSliderEvent = (id, property, displayId = null, isFloat = false) => {
            const slider = $(id);
            if (!slider) return;
            slider.oninput = e => {
                const value = isFloat ? parseFloat(e.target.value) : parseInt(e.target.value, 10);
                params[property] = value;
                if (displayId && $(displayId)) $(displayId).textContent = e.target.value;
                updatePromptParams();
            };
        };
bindSliderEvent('stylize', 'stylize', 'stylize-value');
        bindSliderEvent('weird', 'weird', 'weird-value');
        bindSliderEvent('chaos', 'chaos', 'chaos-value');
        bindSliderEvent('stop-slider', 'stop', 'stop-value');
        bindSliderEvent('r-slider', 'r', 'r-value');
const qualitySlider = $('quality-slider');
        const qualityValueDisplay = $('quality-value');
        const qualityMap = [0.25, 0.5, 1, 2, 4];
if (qualitySlider && qualityValueDisplay) {
            const initialQualityValue = params.quality;
            const initialSliderIndex = qualityMap.indexOf(initialQualityValue);
if (initialSliderIndex !== -1) {
                qualitySlider.value = initialSliderIndex;
                qualityValueDisplay.textContent = initialQualityValue;
            } else {
                params.quality = 1;
                qualitySlider.value = qualityMap.indexOf(1);
                qualityValueDisplay.textContent = params.quality;
            }
qualitySlider.oninput = e => {
                const sliderIndex = parseInt(e.target.value, 10);
                if (sliderIndex >= 0 && sliderIndex < qualityMap.length) {
                    params.quality = qualityMap[sliderIndex];
                    if (qualityValueDisplay) qualityValueDisplay.textContent = params.quality;
                    updatePromptParams();
                }
            };
        }
const bindRadioGroup = (groupClass, property, 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', '');
// MODIFIED bindToggleSwitch: Only binds event, visual update is separate
        const bindToggleSwitchEvent = (switchId, property) => {
            const switchEl = $(switchId);
            if (!switchEl) return;
            switchEl.addEventListener('click', () => {
                params[property] = !params[property];
                updateToggleVisuals(switchId, property); // Update visuals using the new function
                updatePromptParams();
            });
        };
bindToggleSwitchEvent('tile-toggle-switch', 'tile');
        bindToggleSwitchEvent('draft-toggle-switch', 'draft');
// Set initial visual state for toggles
        updateToggleVisuals('tile-toggle-switch', 'tile');
        updateToggleVisuals('draft-toggle-switch', 'draft');
if ($('version-select')) {
            $('version-select').onchange = e => { params.version = e.target.value; updatePromptParams(); };
        }
        if ($('no-prompt')) {
            $('no-prompt').oninput = e => { params.noPrompt = e.target.value.trim(); updatePromptParams(); };
        }
if ($('copy-btn')) {
            $('copy-btn').onclick = () => {
                const textarea = $('prompt-params');
                if (!textarea) return;
                textarea.select();
                try {
                    document.execCommand('copy');
                    showToast('参数已复制!');
                } catch (err) {
                    showToast('复制失败!');
                    console.error('Copy failed:', err);
                }
            };
        }
const sizeMap = ['1:2', '9:16', '2:3', '3:4', '5:6', '1:1', '6:5', '4:3', '3:2', '16:9', '2:1'];
if ($('clear-btn')) {
            $('clear-btn').onclick = () => {
                resetParams(); // params.draft and params.tile will be false
if ($('main-prompt')) $('main-prompt').value = params.prompt;
                if ($('stylize')) $('stylize').value = params.stylize;
                if ($('stylize-value')) $('stylize-value').textContent = params.stylize;
                if ($('weird')) $('weird').value = params.weird;
                if ($('weird-value')) $('weird-value').textContent = params.weird;
                if ($('chaos')) $('chaos').value = params.chaos;
                if ($('chaos-value')) $('chaos-value').textContent = params.chaos;
                if ($('version-select')) $('version-select').value = params.version;
                if ($('no-prompt')) $('no-prompt').value = params.noPrompt;
                if ($('ratio-slider')) {
                    const defaultRatioIndex = sizeMap.indexOf(params.ar);
                    $('ratio-slider').value = defaultRatioIndex !== -1 ? defaultRatioIndex : 5;
                    $('ratio-slider').dispatchEvent(new Event('input'));
                }
['cref-url', 'cref-weight', 'sref-url', 'sref-weight', 'oref-url', 'oref-weight', 'direct-image-url', 'direct-image-weight'].forEach(id => {
                    if ($(id)) $(id).value = '';
                });
if ($('seed-input')) $('seed-input').value = params.seed;
if ($('quality-slider') && qualityMap) {
                    const resetSliderIndex = qualityMap.indexOf(params.quality);
                    $('quality-slider').value = resetSliderIndex !== -1 ? resetSliderIndex : qualityMap.indexOf(1);
                }
                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;
// DO NOT re-bind. Instead, update their visuals.
                updateToggleVisuals('tile-toggle-switch', 'tile');
                updateToggleVisuals('draft-toggle-switch', 'draft');
setInitialActiveButtons();
                refreshPreviews();
                updatePromptParams();
                showToast('所有参数已重置为默认值');
            };
        }
// Updated calls to setupRefSection
        setupRefSection('cref', 'cref');
        setupRefSection('sref', 'sref');
        setupRefSection('oref', 'oref');
        setupRefSection('direct-image', 'directImages'); // idPrefix is 'direct-image', paramKey is 'directImages'
const ratioPresets = { '1:2': { width: 50, height: 100 }, '9:16': { width: 56.25, height: 100 }, '2:3': { width: 66.67, height: 100 }, '3:4': { width: 75, height: 100 }, '5:6': { width: 83.33, height: 100 }, '1:1': { width: 100, height: 100 }, '6:5': { width: 100, height: 83.33 }, '4:3': { width: 100, height: 75 }, '3:2': { width: 100, height: 66.67 }, '16:9': { width: 100, height: 56.25 }, '2:1': { width: 100, height: 50 }};
const ratioSlider = $('ratio-slider');
        if (ratioSlider) {
            ratioSlider.oninput = e => {
                const ratio = sizeMap[+e.target.value] || '1:1';
                params.ar = ratio;
                const box = $('ratio-box');
                const preset = ratioPresets[ratio] || { width: 100, height: 100 };
                if(box) {
                    box.style.width = `${preset.width}px`;
                    box.style.height = `${preset.height}px`;
                    box.textContent = ratio;
                }
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;
            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]) { // This condition might be redundant now due to above
                    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';
            });
            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'; // Darken non-active buttons on hover
                    // else it will use CSS hover or remain its light mode default
                }
            });
            btn.addEventListener('mouseleave', () => {
                 if (!btn.classList.contains('active') && !btn.id.startsWith('theme-toggle')) { // Added check for theme toggle
                    btn.style.transform = originalTransform || 'translateY(0)';
                    btn.style.boxShadow = originalShadow || 'none';
                    if (isDarkMode) btn.style.backgroundColor = '#40444B'; // Restore dark non-active button bg
                    // else it will revert to its original light mode color or CSS default
                 }
            });
        });
    }
function addPreviewImage(containerId, url, weight, paramKey, currentWeightPrefix) { // paramKey is used for deletion
        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>`;
             if(isDarkMode) {
                const errorDiv = imgContainer.firstChild;
                errorDiv.style.background = '#40444B';
                errorDiv.style.color = '#aaa';
            }
        };
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 = currentWeightPrefix ? currentWeightPrefix.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[paramKey]; // Use paramKey to find the correct array in params
                if (Array.isArray(targetArray)) {
                    const index = targetArray.findIndex(item => item.url === url);
                    if (index !== -1) {
                        targetArray.splice(index, 1);
                        if (container.contains(imgContainer)) container.removeChild(imgContainer);
                        updatePromptParams();
                    }
                }
            }, 200);
        };
        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 (isDarkMode) { // Adjusted 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 (isDarkMode) { // Adjusted for 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;';
        if (isDarkMode) { // Adjusted for dark mode
            deleteBtn.style.background = 'rgba(239, 68, 68, 0.3)';
            deleteBtn.style.color = '#FAA';
        }
        deleteBtn.innerHTML = '&times;';
deleteBtn.onclick = function(e) {
            e.stopPropagation();
            codeContainer.style.animation = 'fadeOut 0.2s ease forwards';
            setTimeout(() => {
                const index = params.sref.findIndex(item => item.url === code); // sref is specific here
                if (index !== -1) {
                    params.sref.splice(index, 1);
                    if (container.contains(codeContainer)) container.removeChild(codeContainer);
                    updatePromptParams();
                }
            }, 200);
        };
// Hover effect for delete button, adjusted for dark mode
        const originalDeleteBg = isDarkMode ? 'rgba(239, 68, 68, 0.3)' : 'rgba(239, 68, 68, 0.1)';
        const hoverDeleteBg = isDarkMode ? 'rgba(239, 68, 68, 0.4)' : 'rgba(239, 68, 68, 0.2)';
        deleteBtn.addEventListener('mouseenter', () => { deleteBtn.style.backgroundColor = hoverDeleteBg; });
        deleteBtn.addEventListener('mouseleave', () => { deleteBtn.style.backgroundColor = originalDeleteBg; });
codeContainer.appendChild(codeText);
        codeContainer.appendChild(weightBadge);
        codeContainer.appendChild(deleteBtn);
        container.appendChild(codeContainer);
    }
function refreshPreviews() {
        // paramKey here corresponds to the key in the params object and weightPrefixes map
        const refTypes = [
            { idPrefix: 'cref', paramKey: 'cref', previewId: 'cref-preview' },
            { idPrefix: 'sref', paramKey: 'sref', previewId: 'sref-preview' },
            { idPrefix: 'oref', paramKey: 'oref', previewId: 'oref-preview' },
            { idPrefix: 'direct-image', paramKey: 'directImages', previewId: 'direct-image-preview' }
        ];
refTypes.forEach(ref => {
            const container = document.getElementById(ref.previewId);
            if (!container) return;
            container.innerHTML = ''; // 清除现有预览
const items = params[ref.paramKey];
            if (items && Array.isArray(items)) {
                items.forEach(item => {
                    const currentWeightPrefix = weightPrefixes[ref.paramKey];
                    if (ref.paramKey === 'sref' && (item.url === 'random' || /^\d+$/.test(item.url))) {
                        addPreviewSrefCode(ref.previewId, item.url, item.weight);
                    } else {
                        addPreviewImage(ref.previewId, item.url, item.weight, ref.paramKey, currentWeightPrefix);
                    }
                });
            }
        });
    }
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;}
/* Dark mode styles for range inputs */
            html[data-theme='dark'] input[type="range"]::-webkit-slider-runnable-track,
            body[style*="background-color: rgb(43, 45, 49)"] input[type="range"]::-webkit-slider-runnable-track { /* A bit more specific for Discord's dark */
                background: #40444B; /* var(--track-bg) */
            }
            html[data-theme='dark'] input[type="range"]::-moz-range-track,
            body[style*="background-color: rgb(43, 45, 49)"] input[type="range"]::-moz-range-track {
                background: #40444B; /* var(--track-bg) */
            }
            html[data-theme='dark'] input[type="range"]::-webkit-slider-thumb,
            body[style*="background-color: rgb(43, 45, 49)"] input[type="range"]::-webkit-slider-thumb {
                background-color: #DCDDDE; /* var(--thumb-bg) */
                border-color: #B9BBBE;
            }
            html[data-theme='dark'] input[type="range"]::-moz-range-thumb,
            body[style*="background-color: rgb(43, 45, 49)"] input[type="range"]::-moz-range-thumb {
                background-color: #DCDDDE; /* var(--thumb-bg) */
                border-color: #B9BBBE;
            }
        `;
        document.head.appendChild(styleSheet);
// Check if Font Awesome is already loaded to avoid duplicates if other scripts use it.
        if (!document.querySelector('link[href*="font-awesome"]')) {
            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'; // Consider a specific version or SRI
            document.head.appendChild(faLink);
        }
    }
function init() {
        injectStyles();
        resetParams(); // Initialize params with defaults
        createSettingButton();
        createControlPanel(); // This calls bindControlEvents internally
        setInitialActiveButtons(); // Set active states for radio-like buttons
        updatePromptParams(); // Populate the final prompt field initially
    }
const discordAppMount = document.getElementById('app-mount');
    if (discordAppMount) {
        init();
    } else {
        window.addEventListener('load', init, { once: true });
    }
})();