Sets style="max-width: 100%;" on some elements, unsets max-width on .chat-session-content and #account-switcher, and fixes word breaks on citations.
// ==UserScript==
// @name Google AI Studio Width Fix
// @namespace http://tampermonkey.net/
// @version 1.5
// @description Sets style="max-width: 100%;" on some elements, unsets max-width on .chat-session-content and #account-switcher, and fixes word breaks on citations.
// @author Ȼaptain Jøhn “Søap” MacTavish
// @match https://aistudio.google.com/*
// @grant none
// @run-at document-idle
// @license CC-BY-NC-SA-4.0
// ==/UserScript==
(
function()
{
'use strict';
// Selector for elements to have max-width set to 100%.
const SetSelector = '.ng-star-inserted, .mat-mdc-tooltip-trigger.prompt-input-wrapper';
// Selector for elements to have max-width unset.
const UnsetSelector = '.chat-session-content, ms-prompt-box, #account-switcher';
// Selector for elements to have word-break set to break-all.
const WordBreakSelector = 'ms-citation';
/**
* Applies 'max-width: 100%' to all matching elements.
*
* @param {Node} RootElement The element to search within.
*/
const ApplySetStyles = (RootElement = document) =>
{
const Elements = RootElement.querySelectorAll(SetSelector);
Elements.forEach
(
(ElementNode) =>
{
if (ElementNode.style.maxWidth !== '100%')
{
ElementNode.style.maxWidth = '100%';
}
}
);
};
/**
* Unsets 'max-width' (sets to 'none') on all matching elements.
*
* @param {Node} RootElement The element to search within.
*/
const ApplyUnsetStyles = (RootElement = document) =>
{
const Elements = RootElement.querySelectorAll(UnsetSelector);
Elements.forEach
(
(ElementNode) =>
{
if (ElementNode.style.maxWidth !== 'none')
{
ElementNode.style.maxWidth = 'none';
}
}
);
};
/**
* Applies 'word-break: break-all' to all matching elements.
*
* @param {Node} RootElement The element to search within.
*/
const ApplyWordBreakStyles = (RootElement = document) =>
{
const Elements = RootElement.querySelectorAll(WordBreakSelector);
Elements.forEach
(
(ElementNode) =>
{
if (ElementNode.style.wordBreak !== 'break-all')
{
ElementNode.style.wordBreak = 'break-all';
}
}
);
};
/**
* The callback function for the MutationObserver.
* Applies styles to newly added nodes.
*
* @param {Array<MutationRecord>} MutationsList The list of mutations.
* @param {MutationObserver} ObserverInstance The observer instance.
*/
const ObserverCallback = (MutationsList, ObserverInstance) =>
{
for (const Mutation of MutationsList)
{
if (Mutation.type === 'childList')
{
Mutation.addedNodes.forEach
(
(Node) =>
{
// Ensure the node is an Element (nodeType 1)
if (Node.nodeType === 1)
{
// Apply styles to the new node and its descendants
ApplySetStyles(Node);
ApplyUnsetStyles(Node);
ApplyWordBreakStyles(Node);
// Check if the node itself matches the selectors
if (Node.matches(SetSelector))
{
Node.style.maxWidth = '100%';
}
if (Node.matches(UnsetSelector))
{
Node.style.maxWidth = 'none';
}
if (Node.matches(WordBreakSelector))
{
Node.style.wordBreak = 'break-all';
}
}
}
);
}
}
};
// --- Initialization ---
// 1. Apply styles to elements present on initial load
ApplySetStyles();
ApplyUnsetStyles();
ApplyWordBreakStyles();
// 2. Observe the DOM for dynamically added content
const DomObserver = new MutationObserver(ObserverCallback);
const ObserverConfig =
{
childList: true,
subtree: true
};
DomObserver.observe(document.body, ObserverConfig);
}
)();