T3 Chat wide code block (always expand)

Utilize available horizontal space in T3 Chat to make reading code blocks with very long lines on wide screens easier.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         T3 Chat wide code block (always expand)
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  Utilize available horizontal space in T3 Chat to make reading code blocks with very long lines on wide screens easier.
// @author       https://github.com/dicksonhk, https://t3.chat
// @license      MIT
// @match        https://beta.t3.chat/*
// @match        https://t3.chat/*
// @grant        GM_addStyle // Grant GM_addStyle for the first part
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  const ALWAYS_EXPAND_CODEBLOCK = true;
  const EXPANDED_CODEBLOCK_WIDTH = 'fit-content';
  const MAX_CODEBLOCK_WIDTH = '100%';

  // The original max-width for the wrapper, needs to match [role="log"]'s max-width
  const WRAPPER_MAX_WIDTH = '48rem';

  const _S_LOG_SPECIFIC = `[role="log"].max-w-3xl.px-4`;
  const _S_LOG_FALLBACK = `[role="log"]`;
  const S_LOGS = [_S_LOG_SPECIFIC, _S_LOG_FALLBACK];

  const _S_MSG_GP_SPECIFIC = `${_S_LOG_SPECIFIC} > * > .max-w-full`;
  const _S_MSG_GP_FALLBACK = `${_S_LOG_FALLBACK} :has(> [role="article"])`;
  const S_MSG_GP = [_S_MSG_GP_SPECIFIC, _S_MSG_GP_FALLBACK];

  // absolute and non-absolute items are styled differently
  const S_MSG_GP_ITEMS = S_MSG_GP.map((group) => `${group} > :not(.absolute)`);
  const S_MSG_GP_ABSOLUTE_ITEMS = S_MSG_GP.map((group) => `${group} > .absolute`);

  const CUSTOM_CSS = `
/* Remove max-width constraint wrapper full width and center children */
${[
  ...S_LOGS.map((log) => `${log} > *:not(:has(> .max-w-full))`),
  ...S_LOGS,
].join(',\n')} {
    max-width: 100%;
    align-items: center;
}
/* Apply full width to wrapper direct children */
${[
  ...S_LOGS.map((log) => `${log} > *:not(.absolute)`),
].join(',\n')} {
    width: 100%;
}
/* Apply code blocks width */
${[
  ...(ALWAYS_EXPAND_CODEBLOCK
    ? S_MSG_GP_ITEMS.map((item) => `${item} > :has(pre)`)
    : S_MSG_GP_ITEMS.map((item) => `${item} > :has(.\\[\\&_pre\\]\\:whitespace-pre-wrap > pre)`)
  ),
].join(',\n')} {
    width: ${EXPANDED_CODEBLOCK_WIDTH};
    max-width: min(100%, ${MAX_CODEBLOCK_WIDTH});
    min-width: min(100%, 48rem);
    margin-left: auto;
    margin-right: auto;
}
/* Apply wrapper's original max-width to select children, except for text-wrap enabled code blocks */
/* TODO: handle non top-level code blocks */
${[
  ...S_LOGS.map((log) => `${log} > :not(:has(> .max-w-full)):not(.absolute)`),
  ...S_MSG_GP_ITEMS.map((item) => `${item} > :not(:has(pre))`),
  ...(ALWAYS_EXPAND_CODEBLOCK
    ? []
    : S_MSG_GP_ITEMS.map((item) => `${item} > :not(:has(.\\[\\&_pre\\]\\:whitespace-pre-wrap > pre))`)
  ),
].join(',\n')} {
    max-width: ${WRAPPER_MAX_WIDTH};
}
/* Apply full width to absolute wrappers */
${[
  ...S_MSG_GP_ABSOLUTE_ITEMS.map((item) => `${item}.left-0`),
].join(',\n')} {
    right: 0;
}
${[
  ...S_MSG_GP_ABSOLUTE_ITEMS.map((item) => `${item}.right-0`),
].join(',\n')} {
    left: 0;
}
/* Apply wrapper's original max-width to absolutely positioned children */
${[
  ...S_MSG_GP_ABSOLUTE_ITEMS.flatMap((item) => [
    `${item}.left-0::before`,
    `${item}.right-0::after`,
  ]),
].join(',\n')} {
    content: '';
    width: max(0px, calc((100% - ${WRAPPER_MAX_WIDTH}) / 2 - .25rem));
}
/* Other layout fixes */
${[
  ...S_MSG_GP_ITEMS.map((item) => `${item}:not(.absolute)`),
].join(',\n')} {
    position: relative;
}
${[
  ...S_MSG_GP_ITEMS.map((item) => `${item}.flex-col`),
].join(',\n')} {
    align-items: center;
}
${[
  ...S_MSG_GP_ITEMS.map((item) => `${item}:not(.flex-col) > *`),
  // S_MSG_GP_ITEMS.flatMap((item) => [
  //   `${item}:not(.flex-col) > :not(:has(pre))`,
  //   `${item}:not(.flex-col) > :not(:has(.\\[\\&_pre\\]\\:whitespace-pre-wrap > pre))`
  // ]),
].join(',\n')} {
    margin-left: auto;
    margin-right: auto;
}
`;

  injectCss(CUSTOM_CSS);

  // --- Function to add CSS, checking for GM_addStyle ---
  function injectCss(css) {
    // Check if GM_addStyle is available
    if (typeof GM_addStyle === 'function') {
      GM_addStyle(css);
      return;
    }

    // Inject using a style element
    const styleElement = document.createElement('style');
    styleElement.textContent = css;

    // Append to head if available
    if (document.head) {
      document.head.appendChild(styleElement);
      return;
    }

    // As a last resort, append to the document's root element
    // This is less ideal for performance but ensures the style is applied
    document.documentElement.appendChild(styleElement);
  }
})();