您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Makes the Google Gemini conversation window the full width of the browser window and adds buttons to change the input text area height.
当前为
// ==UserScript== // @name Gemini Wide Screen and Input Box Height Adjuster // @namespace http://www.jeffbyers.com // @match https://gemini.google.com/* // @grant none // @version 2.0 // @author Jeff Byers <[email protected]> // @license GPLv3 - http://www.gnu.org/licenses/gpl-3.0.txt // @copyright Copyright (C) 2024, by Jeff Byers <[email protected]> // @icon https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png // @description Makes the Google Gemini conversation window the full width of the browser window and adds buttons to change the input text area height. // @icon https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png // ==/UserScript== (function () { 'use strict'; // global toggles let wideModeEnabled = localStorage.getItem('geminiWideModeEnabled') === 'true'; let buttonCreated = false; let pageReady = false; // global variables for max rows (load from sessionStorage if available) let maxRowsWide = parseInt(sessionStorage.getItem('maxRowsWide'), 10) || 12; let minRowsWide = parseInt(sessionStorage.getItem('minRowsWide'), 10) || 6; let minRowsNormal = parseInt(sessionStorage.getItem('minRowsNormal'), 10) || 3; let maxRowsNormal = parseInt(sessionStorage.getItem('maxRowsNormal'), 10) || 8; // custom trusted types handling let needsTrustedHTML = false; const passThroughFunc = (string, sink) => string; const TTPName = "geminiStylePolicy"; let TP = { createHTML: passThroughFunc, createScript: passThroughFunc, createScriptURL: passThroughFunc, }; try { if ( typeof window.isSecureContext !== "undefined" && window.isSecureContext ) { if (window.trustedTypes && window.trustedTypes.createPolicy) { if (trustedTypes.defaultPolicy) { TP = trustedTypes.defaultPolicy; } else { TP = window.trustedTypes.createPolicy(TTPName, TP); } needsTrustedHTML = true; } } } catch (e) { // log trusted types initialization error console.error("Error initializing Trusted Types:", e); } function trustedHTML(string) { try { return needsTrustedHTML ? TP.createHTML(string) : string; } catch (error) { console.error("Error in trustedHTML:", error, "Original string:", string); // fallback to returning the original string (unsafe, but allows debugging) return string; } } function getNonce() { const cspHeader = document.querySelector('meta[http-equiv="Content-Security-Policy"]'); if (!cspHeader) return null; const cspContent = cspHeader.content; const nonceMatch = cspContent.match(/nonce-(.+?)[';]/); return nonceMatch ? nonceMatch[1] : null; } function resizeStuff() { // directly set max-width const elementsToSetMaxWidth = document.querySelectorAll( 'div.bottom-container, ' + 'div.input-area-container, ' + 'div.conversation-container, ' + '.text-input-field' ); elementsToSetMaxWidth.forEach((element) => { element.style.maxWidth = wideModeEnabled ? '100%' : ''; }); // set --textarea-max-rows dynamically based on wideModeEnabled document.documentElement.style.setProperty('--textarea-max-rows', wideModeEnabled ? maxRowsWide : maxRowsNormal); document.documentElement.style.setProperty('--textarea-min-rows', wideModeEnabled ? Math.max(3, minRowsWide) : Math.max(3, minRowsNormal)); // find and adjust rich-textarea .ql-editor const qlEditors = document.querySelectorAll('rich-textarea .ql-editor'); qlEditors.forEach((editor) => { // Set --textarea-max-rows directly on the rich-textarea element editor.style.setProperty( '--textarea-max-rows', wideModeEnabled ? maxRowsWide : maxRowsNormal ); editor.style.minHeight = 'calc((var(--textarea-min-rows, 0)) * 24px)'; editor.style.maxHeight = 'calc((var(--textarea-max-rows, 0)) * 24px)'; }); } function toggleWideMode() { wideModeEnabled = !wideModeEnabled; resizeStuff(); updateButtonIcon(); // update the icon } function windowSizeUp() { const preFullscreenElements = document.querySelectorAll('.pre-fullscreen'); if (preFullscreenElements.length > 0 && wideModeEnabled) { maxRowsWide++; // increase max rows for wide mode if in fullscreen sessionStorage.setItem('maxRowsWide', maxRowsWide); // store in sessionStorage } else if (preFullscreenElements.length > 0 && !wideModeEnabled) { maxRowsNormal++; // increase max rows for normal mode if in fullscreen sessionStorage.setItem('maxRowsNormal', maxRowsNormal); } else if (!wideModeEnabled) { minRowsNormal++; // increase min rows for normal mode if not in fullscreen sessionStorage.setItem('minRowsNormal', minRowsNormal); } else { minRowsWide++; // increase min rows for wide mode if not in fullscreen sessionStorage.setItem('minRowsWide', minRowsWide); } resizeStuff(); // reapply styles to reflect the changes } function windowSizeDown() { const preFullscreenElements = document.querySelectorAll('.pre-fullscreen'); if (preFullscreenElements.length > 0 && wideModeEnabled) { maxRowsWide = Math.max(minRowsWide, maxRowsWide - 1); // decrease max rows for wide mode if in fullscreen (but not below minRowsWide) sessionStorage.setItem('maxRowsWide', maxRowsWide); // store in sessionStorage } else if (preFullscreenElements.length > 0 && !wideModeEnabled) { maxRowsNormal = Math.max(minRowsNormal, maxRowsNormal - 1); // decrease max rows for normal mode if in fullscreen (but not below minRowsNormal) sessionStorage.setItem('maxRowsNormal', maxRowsNormal); } else if (!wideModeEnabled) { minRowsNormal = Math.max(1, minRowsNormal - 1); // decrease min rows for normal mode if not in fullscreen (but not below 1) sessionStorage.setItem('minRowsNormal', minRowsNormal); } else { minRowsWide = Math.max(1, minRowsWide - 1); // decrease min rows for wide mode if not in fullscreen (but not below 1) sessionStorage.setItem('minRowsWide', minRowsWide); } resizeStuff(); // reapply styles to reflect the changes } // modified addGlobalStyle using CSSStyleSheet (with fallback) function addGlobalStyle(css) { if (window.CSSStyleSheet && CSSStyleSheet.prototype.replaceSync) { const sheet = new CSSStyleSheet(); sheet.replaceSync(trustedHTML(css)); document.adoptedStyleSheets = [sheet]; } else { let head = document.head || document.getElementsByTagName('head')[0]; if (!head) return; let style = document.createElement('style'); style.type = 'text/css'; style.textContent = trustedHTML(css); head.appendChild(style); } } // function to create and insert the button (with error handling) function createToggleButton() { try { const inputButtonsWrapperBottom = document.querySelector('.input-buttons-wrapper-bottom'); const inputButtonsWrapperTop = document.querySelector('.input-buttons-wrapper-top'); if (!inputButtonsWrapperBottom || !inputButtonsWrapperTop) { console.log("One or both wrappers not found. Retrying..."); setTimeout(createToggleButton, 100); // Retry after a delay return; // Exit the function if either wrapper is not found } // Check for existing buttons using a unique identifier (e.g., aria-label) if (inputButtonsWrapperTop.querySelector('[aria-label="Toggle Wide Mode"]') || inputButtonsWrapperBottom.querySelector('[aria-label="Window Size Up"]') || inputButtonsWrapperBottom.querySelector('[aria-label="Window Size Down"]')) { console.log("Buttons already exist. Skipping creation."); return; // Exit the function if any button already exists } // Create the buttons using Trusted Types const toggleButtonHTML = trustedHTML(` <div class="speech-dictation-mic-button ng-star-inserted"> <button data-node-type="speech_dictation_mic_button" maticonsuffix="" mat-icon-button="" mattooltip="Wide Mode" aria-label="Toggle Wide Mode" class="wide-screen-button mat-mdc-tooltip-trigger speech_dictation_mic_button mdc-icon-button mat-mdc-icon-button gmat-mdc-button-with-prefix mat-unthemed mat-mdc-button-base gmat-mdc-button"> <span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span> <div> <span class="mat-icon notranslate google-symbols mat-icon-no-color" id="wide_screen_image" data-mat-iic class="material-symbols-outlined"></span> </div> <span class="mat-mdc-focus-indicator"></span> <span class="mat-mdc-button-touch-target"></span> </button> </div> `); const SizeButtonsHTML = trustedHTML(` <div class="speech-dictation-mic-button ng-star-inserted"> <button data-node-type="speech_dictation_mic_button" maticonsuffix="" mat-icon-button="" mattooltip="Size Down" aria-label="Window Size Down" class="wide-screen-button mat-mdc-tooltip-trigger speech_dictation_mic_button mdc-icon-button mat-mdc-icon-button gmat-mdc-button-with-prefix mat-unthemed mat-mdc-button-base gmat-mdc-button"> <span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span> <div> <span class="mat-icon notranslate google-symbols mat-icon-no-color" data-mat-iic class="material-symbols-outlined">keyboard_arrow_down</span> </div> <span class="mat-mdc-focus-indicator"></span> <span class="mat-mdc-button-touch-target"></span> </button> </div> <div class="speech-dictation-mic-button ng-star-inserted"> <button data-node-type="speech_dictation_mic_button" maticonsuffix="" mat-icon-button="" mattooltip="Size Up" aria-label="Window Size Up" class="wide-screen-button mat-mdc-tooltip-trigger speech_dictation_mic_button mdc-icon-button mat-mdc-icon-button gmat-mdc-button-with-prefix mat-unthemed mat-mdc-button-base gmat-mdc-button"> <span class="mat-mdc-button-persistent-ripple mdc-icon-button__ripple"></span> <div> <span class="mat-icon notranslate google-symbols mat-icon-no-color" data-mat-iic class="material-symbols-outlined">keyboard_arrow_up</span> </div> <span class="mat-mdc-focus-indicator"></span> <span class="mat-mdc-button-touch-target"></span> </button> </div> `); // use insertAdjacentHTML to add the buttons inputButtonsWrapperTop.insertAdjacentHTML('afterbegin', toggleButtonHTML); inputButtonsWrapperBottom.insertAdjacentHTML('afterend', SizeButtonsHTML); // add click event listeners const toggleButton = document.querySelector('[aria-label="Toggle Wide Mode"]'); const sizeUpButton = document.querySelector('[aria-label="Window Size Up"]'); const sizeDownButton = document.querySelector('[aria-label="Window Size Down"]'); toggleButton.addEventListener('click', toggleWideMode); sizeUpButton.addEventListener('click', windowSizeUp); sizeDownButton.addEventListener('click', windowSizeDown); buttonCreated = true; console.log('Buttons created successfully! We\'re done.'); } catch (error) { console.error("Error in createToggleButton:", error); } } // have to set pre-fullscreen globally as the elements don't exist when the page loads addGlobalStyle(trustedHTML(` div .pre-fullscreen { height: auto !important; } div .input-buttons-wrapper-top { right: 8px !important; } div .isFullscreen { max-height: 100% !important; } `)); // function to update the button icon based on wideModeEnabled function updateButtonIcon() { const iconSpan = document.getElementById("wide_screen_image"); if (iconSpan) { iconSpan.textContent = wideModeEnabled ? 'remove' : 'add'; } // Store the updated state in localStorage localStorage.setItem('geminiWideModeEnabled', wideModeEnabled); } // function to check if page is loaded and ready for our button function checkIfPageReadyForButton() { if (document.readyState === 'complete' && !buttonCreated) { pageReady = true; console.log('Page is ready. Now make the button.'); createToggleButton(); } } // callback function for the MutationObserver function mutationObserverCallback() { checkIfPageReadyForButton(); // check if button needs to be created updateButtonIcon(); resizeStuff(); // apply or update styles } // initial check and then MutationObserver to handle potential changes checkIfPageReadyForButton(); const observer = new MutationObserver(mutationObserverCallback); observer.observe(document.body, { childList: true, subtree: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址