Gemini宽屏 (动态适配版)

动态适配ChatGPT Conversation Timeline插件,并同时加宽input-container及其内部区域。清空底部免责声明文字(保留边距)。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Gemini宽屏 (动态适配版)
// @name:zh-CN   Gemini宽屏 (动态适配版)
// @namespace    https://greasyfork.org/zh-CN/users/lcx04
// @version      2.0
// @description  Dynamically adapts for the 'ChatGPT Conversation Timeline' plugin. Widens input-container and input-area-container. Clears disclaimer text.
// @description:zh-CN 动态适配ChatGPT Conversation Timeline插件,并同时加宽input-container及其内部区域。清空底部免责声明文字(保留边距)。
// @author       lcx04
// @match        https://gemini.google.com/*
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ----------------------------------------------------------------------
    // 检测目标: "chatgpt-timeline-bar"
    const OTHER_SCRIPT_CLASS = 'chatgpt-timeline-bar';
    // ----------------------------------------------------------------------

    let styleElement = null; // 用来保存我们注入的 <style> 标签的引用

    /**
     * 【新增】查找并清空免责声明的文字
     */
    function clearDisclaimerText() {
        // 使用 data-test-id 精确查找
        const disclaimer = document.querySelector('[data-test-id="disclaimer"]');

        // 检查元素是否存在,并且 *还有文字* (避免重复设置 textContent 导致不必要的性能开销)
        if (disclaimer && disclaimer.textContent !== '') {
            disclaimer.textContent = ''; // 设置为空字符串
            console.log('Wider Gemini: Disclaimer text cleared (JS).');
        }
    }

    /**
     * 检查目标元素是否存在,并应用或更新正确的 CSS
     */
    function applyDynamicStyles() {
        // 检查 'chatgpt-timeline-bar' 元素是否存在
        const timelineExists = document.querySelector('.' + OTHER_SCRIPT_CLASS);

        let customCSS = '';

        if (timelineExists) {
            // 找到了,应用固定的 24px 边距
            console.log('Wider Gemini: "chatgpt-timeline-bar" detected. Applying fixed 24px margin.');
            customCSS = `
                /* --- 聊天记录容器 --- */
                .conversation-container {
                    width: calc(100% - 24px) !important;
                    max-width: 2000px !important;
                    margin-right: 24px !important;
                }
                user-query {
                    max-width: 2000px !important;
                }

                /* --- 输入框容器 (标签选择器) --- */
                input-container {
                    width: calc(100% - 24px) !important;
                    max-width: 2000px !important;
                    margin-right: 24px !important;
                    padding-left: 28px !important;
                    padding-right: 28px !important;
                }

                /* --- 【更新】输入框内部区域 --- */
                .input-area-container,
                .overlay-container {
                    max-width: 2000px !important; /* 保持最大宽度一致 */
                }
            `;
        } else {
            // 没找到,应用 0 边距的全宽样式
            console.log('Wider Gemini: "chatgpt-timeline-bar" NOT detected. Applying 0 margin.');
            customCSS = `
                /* --- 聊天记录容器 --- */
                .conversation-container {
                    width: 100% !important;
                    max-width: 2000px !important;
                    margin-right: 0 !important;
                }
                user-query {
                    max-width: 2000px !important;
                }

                /* --- 输入框容器 (标签选择器) --- */
                input-container {
                    width: 100% !important;
                    max-width: 2000px !important;
                    margin-right: 0 !important;
                    padding-left: 28px !important;
                    padding-right: 28px !important;
                }

                /* --- 【更新】输入框内部区域 --- */
                .input-area-container,
                .overlay-container {
                    max-width: 2000px !important; /* 保持最大宽度一致 */
                }
            `;
        }

        // 注入或更新样式
        if (styleElement) {
            // 如果 <style> 标签已存在,只更新其内容
            styleElement.textContent = customCSS;
        } else {
            // 如果是第一次运行,则创建 <style> 标签
            styleElement = GM_addStyle(customCSS);
        }
    }

    /**
     * 检查 DOM 变动
     * 【修改】: 同时检查 timeline 插件 和 免责声明
     */
    const observerCallback = (mutationsList, observer) => {
        let targetNodeChanged = false; // 标记 timeline 插件是否变化
        let generalDomChange = false;  // 标记是否发生了 DOM 变化(用于检查免责声明)

        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                generalDomChange = true; // 只要有子节点变动,就标记

                // --- 原有逻辑: 检查 timeline 插件 ---
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1 && (node.classList.contains(OTHER_SCRIPT_CLASS) || node.querySelector('.' + OTHER_SCRIPT_CLASS))) {
                        targetNodeChanged = true;
                    }
                });
                mutation.removedNodes.forEach(node => {
                    if (node.nodeType === 1 && (node.classList.contains(OTHER_SCRIPT_CLASS) || node.querySelector('.' + OTHER_SCRIPT_CLASS))) {
                        targetNodeChanged = true;
                    }
                });
                // --- 结束 ---
            }
        }

        // 如果 timeline 插件发生了变化,才更新 CSS
        if (targetNodeChanged) {
            applyDynamicStyles();
        }

        // 只要 DOM 发生了变动,就(重新)检查并清空免责声明的文字
        // 因为 Gemini 是 SPA,这个元素可能在切换页面或生成回答时被重新渲染
        if (generalDomChange) {
            clearDisclaimerText();
        }
    };

    // --- 脚本执行 ---

    // 1. 创建并启动 MutationObserver 来监听 DOM 变化
    const observer = new MutationObserver(observerCallback);

    // 确保 <body> 存在后再开始监听
    const startObserver = () => {
        if (document.body) {
            observer.observe(document.body, { childList: true, subtree: true });

            // 立即运行一次检查(样式)
            applyDynamicStyles();
            // 立即运行一次检查(清空文字)
            clearDisclaimerText();
        } else {
            // 如果 body 还没加载,稍后再试
            setTimeout(startObserver, 100);
        }
    };

    startObserver();

    console.log('Wider Gemini (Dynamic Adapter) script v2.0 loaded.');
})();