Gemini Singularity (V5.7 Lite++)

Gemini 聊天页面轻量美化:更舒服的排版 + 发光代码块 & 表格(保持原生布局),主题自适应 + 可访问性增强。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Gemini Singularity (V5.7 Lite++)
// @namespace    http://tampermonkey.net/
// @version      5.7
// @description  Gemini 聊天页面轻量美化:更舒服的排版 + 发光代码块 & 表格(保持原生布局),主题自适应 + 可访问性增强。
// @author       GQLJ + GPT
// @match        https://gemini.google.com/*
// @icon         data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCI+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJnIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiMxMTE4MjciLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjMDIwNjE3Ii8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50IGlkPSJnbG93IiBjeD0iNTAlIiBjeT0iMCUiIHI9IjcwJSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiM2MGE1ZmEiIHN0b3Atb3BhY2l0eT0iMC45Ii8+CiAgICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzFkNGVkOCIgc3RvcC1vcGFjaXR5PSIwLjAiLz4KICAgIDwvcmFkaWFsR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxyZWN0IHg9IjQiIHk9IjQiIHdpZHRoPSI1NiIgaGVpZ2h0PSI1NiIgcng9IjE0IiBmaWxsPSJ1cmwoI2JnKSIvPgogIDxjaXJjbGUgY3g9IjMyIiBjeT0iMTgiIHI9IjE4IiBmaWxsPSJ1cmwoI2dsb3cpIiAvPgogIDx0ZXh0IHg9IjUwJSIgeT0iNTYlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjZTVlN2ViIiBmb250LWZhbWlseT0ic3lzdGVtLXVpLCAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsICdTZWdvZSBVSScsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMzAiIGZvbnQtd2VpZ2h0PSI3MDAiPgogICAgRwogIDwvdGV4dD4KPC9zdmc+
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  const DEBUG = false;
  if (window.top !== window.self) return;

  // =========================
  //  可配置项(菜单开关)
  // =========================
  const DEFAULTS = {
    maxWidth: 980,
    fontSize: 17,
    fontSizeMobile: 16,

    enableRemoteFonts: true,
    enableGlow: true,
    enableEntryAnim: true,
    justifyText: true,
    roundImages: true,
    tableMobileScroll: true,
  };

  const cfg = {
    maxWidth: Number(GM_getValue('maxWidth', DEFAULTS.maxWidth)),
    fontSize: Number(GM_getValue('fontSize', DEFAULTS.fontSize)),
    fontSizeMobile: Number(GM_getValue('fontSizeMobile', DEFAULTS.fontSizeMobile)),

    enableRemoteFonts: !!GM_getValue('enableRemoteFonts', DEFAULTS.enableRemoteFonts),
    enableGlow: !!GM_getValue('enableGlow', DEFAULTS.enableGlow),
    enableEntryAnim: !!GM_getValue('enableEntryAnim', DEFAULTS.enableEntryAnim),
    justifyText: !!GM_getValue('justifyText', DEFAULTS.justifyText),
    roundImages: !!GM_getValue('roundImages', DEFAULTS.roundImages),
    tableMobileScroll: !!GM_getValue('tableMobileScroll', DEFAULTS.tableMobileScroll),
  };

  function toggle(key) {
    GM_setValue(key, !cfg[key]);
    window.location.reload();
  }

  try {
    GM_registerMenuCommand(`远程字体: ${cfg.enableRemoteFonts ? '开' : '关'}`, () => toggle('enableRemoteFonts'));
    GM_registerMenuCommand(`发光效果: ${cfg.enableGlow ? '开' : '关'}`, () => toggle('enableGlow'));
    GM_registerMenuCommand(`入场动画: ${cfg.enableEntryAnim ? '开' : '关'}`, () => toggle('enableEntryAnim'));
    GM_registerMenuCommand(`段落两端对齐: ${cfg.justifyText ? '开' : '关'}`, () => toggle('justifyText'));
    GM_registerMenuCommand(`图片圆角: ${cfg.roundImages ? '开' : '关'}`, () => toggle('roundImages'));
    GM_registerMenuCommand(`移动端表格横滑: ${cfg.tableMobileScroll ? '开' : '关'}`, () => toggle('tableMobileScroll'));
  } catch (_) {}

  // =========================
  //  字体加载(可关)— 用 link 替代 @import
  // =========================
  function injectFonts() {
    if (!cfg.enableRemoteFonts) return;
    const head = document.head || document.documentElement;

    const pre1 = document.createElement('link');
    pre1.rel = 'preconnect';
    pre1.href = 'https://fonts.googleapis.com';
    head.appendChild(pre1);

    const pre2 = document.createElement('link');
    pre2.rel = 'preconnect';
    pre2.href = 'https://fonts.gstatic.com';
    pre2.crossOrigin = 'anonymous';
    head.appendChild(pre2);

    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href =
      'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;750&family=JetBrains+Mono:wght@400;500;600&display=swap';
    head.appendChild(link);
  }
  injectFonts();

  // =========================
  //  阴影强度(可关)
  // =========================
  const glowShadows = cfg.enableGlow
    ? `
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.04),
        0 0 22px var(--singularity-glow-soft),
        0 22px 55px -18px rgba(0,0,0,0.7) !important;
    `
    : `
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.04),
        0 18px 45px -22px rgba(0,0,0,0.55) !important;
    `;

  const glowShadowsHover = cfg.enableGlow
    ? `
      box-shadow:
        0 0 0 1px var(--singularity-glow-strong),
        0 0 40px var(--singularity-glow-strong),
        0 25px 65px -20px rgba(0,0,0,0.85) !important;
    `
    : `
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.06),
        0 22px 55px -24px rgba(0,0,0,0.75) !important;
    `;

  const tableShadows = cfg.enableGlow
    ? `
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.03),
        0 0 18px var(--singularity-glow-soft),
        0 4px 20px rgba(0,0,0,0.05);
    `
    : `
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.03),
        0 4px 18px rgba(0,0,0,0.05);
    `;

  const tableShadowsHover = cfg.enableGlow
    ? `
      box-shadow:
        0 0 0 1px var(--singularity-glow-strong),
        0 0 28px var(--singularity-glow-strong),
        0 6px 28px rgba(0,0,0,0.12);
    `
    : `
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.05),
        0 6px 26px rgba(0,0,0,0.12);
    `;

  const entryAnimCSS = cfg.enableEntryAnim
    ? `
      @keyframes singularFadeIn {
        0% { opacity: 0; transform: translateY(8px); }
        100% { opacity: 1; transform: translateY(0); }
      }
      .model-response-text > :is(p, h1, h2, h3, h4, blockquote, table, ul, ol, code-block, mjx-container[display="true"]),
      markdown-renderer > :is(p, h1, h2, h3, h4, blockquote, table, ul, ol, code-block, mjx-container[display="true"]) {
        animation: singularFadeIn 0.45s var(--ease-out-expo) both;
      }
    `
    : `
      .model-response-text > *,
      markdown-renderer > * { animation: none !important; }
    `;

  const justifyCSS = cfg.justifyText
    ? `
      :where(.model-response-text, markdown-renderer) p {
        text-align: justify;
        text-justify: inter-ideograph;
      }
    `
    : `
      :where(.model-response-text, markdown-renderer) p { text-align: left; }
    `;

  const imagesCSS = cfg.roundImages
    ? `
      :where(.model-response-text, markdown-renderer) img {
        max-width: 100%;
        height: auto;
        border-radius: 14px;
        box-shadow: 0 8px 28px rgba(0,0,0,0.08);
      }
    `
    : `
      :where(.model-response-text, markdown-renderer) img {
        max-width: 100%;
        height: auto;
      }
    `;

  const tableMobileCSS = cfg.tableMobileScroll
    ? `
      @media (max-width: 768px) {
        :where(.model-response-text, markdown-renderer) table {
          display: block;
          overflow-x: auto;
          -webkit-overflow-scrolling: touch;
        }
      }
    `
    : '';

  // =========================
  //  CSS
  // =========================
  const css = `
    :root {
      --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
      --glass-blur: blur(20px) saturate(180%);

      --body-font: ${cfg.enableRemoteFonts ? `'Inter', ` : ''}system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      --code-font: ${cfg.enableRemoteFonts ? `'JetBrains Mono', ` : ''}'Fira Code', 'Menlo', ui-monospace, SFMono-Regular, monospace;

      --accent: #4285f4;
      --accent-strong: #1a73e8;
      --accent-soft: rgba(66, 133, 244, 0.08);

      --singularity-glow-soft: rgba(138, 180, 248, 0.26);
      --singularity-glow-strong: rgba(138, 180, 248, 0.55);

      --singularity-max-width: ${cfg.maxWidth}px;
      --singularity-font-size: ${cfg.fontSize}px;
      --singularity-font-size-mobile: ${cfg.fontSizeMobile}px;

      /* 代码块:主题自适应变量(默认按浅色) */
      --sg-code-bg: var(--gm-surface-variant, #f6f7f8);
      --sg-code-text: var(--gm-on-surface, #202124);
      --sg-code-border: var(--gm-outline-variant, rgba(0,0,0,0.10));
      --sg-code-header-bg: rgba(255,255,255,0.75);
      --sg-code-header-sep: rgba(0,0,0,0.06);

      scrollbar-width: thin;
      scrollbar-color: var(--gm-outline-variant, rgba(128,128,128,0.2)) transparent;
    }

    /* 深色主题兜底 */
    @media (prefers-color-scheme: dark) {
      :root {
        --sg-code-bg: #050608;
        --sg-code-text: #e4e4e4;
        --sg-code-border: var(--gm-outline-variant, rgba(255,255,255,0.12));
        --sg-code-header-bg: rgba(30, 30, 30, 0.6);
        --sg-code-header-sep: rgba(255,255,255,0.06);
      }
    }

    body {
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-rendering: optimizeLegibility;
    }

    ::-webkit-scrollbar { width: 6px; height: 6px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb {
      background: var(--gm-outline-variant, rgba(128,128,128,0.2));
      border-radius: 99px;
      border: 2px solid transparent;
      background-clip: content-box;
    }
    ::-webkit-scrollbar-thumb:hover { background-color: var(--gm-outline, rgba(128,128,128,0.5)); }

    .conversation-container,
    .bottom-container,
    .input-area-container {
      max-width: var(--singularity-max-width) !important;
      margin: 0 auto !important;
      padding-inline: 12px;
    }

    ::selection { background: rgba(66, 133, 244, 0.25); color: inherit; }

    ${entryAnimCSS}

    @media (prefers-reduced-motion: reduce) {
      .model-response-text > *,
      markdown-renderer > * { animation: none !important; }
      code-block,
      .model-response-text table,
      markdown-renderer table { transition: none !important; }
    }

    /* 更强的“减少透明/特效”降级(支持就用,不支持也不影响) */
    @media (prefers-reduced-transparency: reduce) {
      code-block, :where(.model-response-text, markdown-renderer) table {
        box-shadow: none !important;
      }
      .code-block-decoration {
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
      }
    }

    /* ====== 正文排版 ====== */
    :where(.model-response-text, markdown-renderer) {
      font-family: var(--body-font) !important;
      font-size: var(--singularity-font-size) !important;
      line-height: 1.85 !important;
      letter-spacing: 0.012em;
      color: var(--gm-on-surface) !important;
      hyphens: auto;
    }

    :where(.model-response-text, markdown-renderer) :is(h1, h2, h3, h4) {
      font-weight: 750 !important;
      letter-spacing: -0.02em;
      margin-top: 1.8em !important;
      margin-bottom: 0.8em !important;
      color: var(--gm-on-surface);
      position: relative;
    }
    :where(.model-response-text, markdown-renderer) h1 { font-size: 1.6em !important; }
    :where(.model-response-text, markdown-renderer) h2 { font-size: 1.35em !important; }
    :where(.model-response-text, markdown-renderer) h3 { font-size: 1.18em !important; }
    :where(.model-response-text, markdown-renderer) h4 { font-size: 1.05em !important; }

    :where(.model-response-text, markdown-renderer) :is(h1, h2, h3, h4)::after {
      content: '';
      position: absolute;
      left: 0;
      bottom: -6px;
      width: 72px;
      height: 2px;
      border-radius: 99px;
      background: linear-gradient(90deg, var(--accent), transparent);
      opacity: 0.55;
    }

    :where(.model-response-text, markdown-renderer) p {
      margin-bottom: 1.8em !important;
      max-width: 100%;
    }

    ${justifyCSS}

    @media (max-width: 768px) {
      :where(.model-response-text, markdown-renderer) {
        font-size: var(--singularity-font-size-mobile) !important;
      }
      :where(.model-response-text, markdown-renderer) p { text-align: left !important; }
    }

    /* 列表 */
    :where(.model-response-text, markdown-renderer) ul li::marker { color: var(--accent); }
    :where(.model-response-text, markdown-renderer) ol li::marker {
      color: var(--accent);
      font-weight: 600;
      font-variant-numeric: tabular-nums;
    }
    :where(.model-response-text, markdown-renderer) li {
      padding-left: 4px;
      margin-bottom: 0.8em !important;
    }

    /* 链接:hover 不抖动 */
    :where(.model-response-text, markdown-renderer) a {
      text-decoration: none !important;
      color: var(--accent-strong) !important;
      border-bottom: 1.5px solid rgba(26, 115, 232, 0.3);
      transition: box-shadow 0.18s ease-out, background 0.18s ease-out, border-color 0.18s ease-out;
      font-weight: 500;
      border-radius: 4px;
    }
    :where(.model-response-text, markdown-renderer) a:hover {
      border-bottom-color: var(--accent-strong);
      background: var(--accent-soft);
      box-shadow: 0 0 0 4px var(--accent-soft);
    }
    @media (prefers-color-scheme: dark) {
      :where(.model-response-text, markdown-renderer) a {
        color: #8ab4f8 !important;
        border-color: rgba(138, 180, 248, 0.35);
      }
    }

    /* ===== 可访问性:键盘 focus ring(范围尽量收在主区) ===== */
    :where(.conversation-container, .bottom-container, .input-area-container)
      :is(a, button, [role="button"], input, textarea, select):focus-visible {
      outline: 2px solid var(--accent) !important;
      outline-offset: 3px !important;
      border-radius: 8px;
      box-shadow: 0 0 0 4px var(--accent-soft) !important;
    }

    /* ====== 代码块(主题自适应) ====== */
    code-block {
      display: block;
      margin: 32px 0 !important;
      border-radius: 16px !important;
      border: 1px solid var(--sg-code-border) !important;
      background: var(--sg-code-bg) !important;
      ${glowShadows}
      overflow: hidden !important;
      position: relative;
      z-index: 1;
      transition: box-shadow 0.22s var(--ease-out-expo), border-color 0.22s var(--ease-out-expo);
    }
    code-block:hover {
      border-color: var(--singularity-glow-strong);
      ${glowShadowsHover}
    }

    .code-block-decoration {
      height: 50px !important;
      display: flex;
      align-items: center;
      padding: 0 22px !important;
      background: var(--sg-code-header-bg) !important;
      border-bottom: 1px solid var(--sg-code-header-sep);
    }
    @supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
      .code-block-decoration {
        backdrop-filter: var(--glass-blur) !important;
        -webkit-backdrop-filter: var(--glass-blur) !important;
      }
    }

    .code-block-decoration::before {
      content: '';
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: #ff5f56;
      box-shadow: 20px 0 0 #ffbd2e, 40px 0 0 #27c93f;
      margin-right: 20px;
      opacity: 0.8;
      transition: opacity 0.3s;
    }
    code-block:hover .code-block-decoration::before { opacity: 1; }

    /* 仅影响 code-block 内 pre */
    code-block pre {
      background: transparent !important;
      padding: 24px !important;
      font-family: var(--code-font) !important;
      font-size: 14.5px !important;
      line-height: 1.7 !important;
      color: var(--sg-code-text) !important;
      text-shadow: none;
      overflow-x: auto;
      tab-size: 4;
    }
    @media (prefers-color-scheme: dark) {
      code-block pre { text-shadow: 0 1px 2px rgba(0,0,0,0.5); }
    }

    /* 行内代码 */
    :where(.model-response-text, markdown-renderer) :not(pre) > code {
      font-family: var(--code-font) !important;
      background: var(--gm-secondary-container, rgba(0,0,0,0.05)) !important;
      color: var(--gm-on-secondary-container, #d93025) !important;
      padding: 4px 8px !important;
      border-radius: 8px !important;
      font-size: 0.85em !important;
      border: 1px solid var(--gm-outline-variant, rgba(0,0,0,0.05));
      vertical-align: baseline;
      font-weight: 600;
      word-break: break-word;
    }

    /* 引用块 */
    :where(.model-response-text, markdown-renderer) blockquote {
      border: none !important;
      position: relative;
      margin: 2.4em 0 !important;
      padding: 1.6em 2em !important;
      background: linear-gradient(
        135deg,
        var(--gm-surface-variant, rgba(66, 133, 244, 0.05)) 0%,
        rgba(66, 133, 244, 0.01) 100%
      );
      border-radius: 16px;
      color: var(--gm-on-surface-variant) !important;
    }
    :where(.model-response-text, markdown-renderer) blockquote::before {
      content: '❝';
      position: absolute;
      top: 10px;
      right: 14px;
      font-size: 28px;
      opacity: 0.18;
      color: var(--accent);
      pointer-events: none;
    }
    :where(.model-response-text, markdown-renderer) blockquote::after {
      content: '';
      position: absolute;
      left: 0;
      top: 12px;
      bottom: 12px;
      width: 3px;
      background: var(--accent);
      border-radius: 0 4px 4px 0;
      box-shadow: 2px 0 8px rgba(66, 133, 244, 0.3);
    }

    /* 表格 */
    :where(.model-response-text, markdown-renderer) table {
      border-collapse: separate !important;
      border-spacing: 0;
      width: 100%;
      margin: 2.4em 0 !important;
      border-radius: 12px;
      overflow: hidden;
      border: 1px solid var(--gm-outline-variant, rgba(128,128,128,0.2));
      ${tableShadows}
      transition: box-shadow 0.22s var(--ease-out-expo), border-color 0.22s var(--ease-out-expo);
    }
    :where(.model-response-text, markdown-renderer) table:hover {
      border-color: var(--singularity-glow-strong);
      ${tableShadowsHover}
    }
    :where(.model-response-text, markdown-renderer) th {
      background: var(--gm-surface-variant, #f1f3f4);
      color: var(--gm-on-surface);
      padding: 16px 18px !important;
      font-weight: 700;
      font-size: 0.95em;
      text-transform: uppercase;
      letter-spacing: 0.05em;
      white-space: nowrap;
    }
    :where(.model-response-text, markdown-renderer) td {
      padding: 14px 18px !important;
      border-top: 1px solid var(--gm-outline-variant, rgba(128,128,128,0.05));
      background: var(--gm-surface, transparent);
      transition: background 0.1s;
    }
    :where(.model-response-text, markdown-renderer) tr:hover td {
      background: var(--gm-secondary-container, rgba(66, 133, 244, 0.05));
    }
    ${tableMobileCSS}

    /* LaTeX */
    :where(.model-response-text, markdown-renderer) mjx-container[display="true"] {
      margin: 2.5em 0 !important;
      padding: 1.5em 2em !important;
      background: var(--gm-surface-variant, rgba(128,128,128,0.03));
      border-radius: 12px;
      border: 1px solid var(--gm-outline-variant, transparent);
      color: var(--gm-on-surface) !important;
      overflow-x: auto;
    }

    ${imagesCSS}

    .input-area-container { padding-bottom: 40px !important; }

    /* ===== 高对比模式/强制颜色:禁用发光/渐变,确保可读 ===== */
    @media (forced-colors: active) {
      code-block,
      :where(.model-response-text, markdown-renderer) table,
      :where(.model-response-text, markdown-renderer) blockquote,
      :where(.model-response-text, markdown-renderer) mjx-container[display="true"] {
        box-shadow: none !important;
        background: Canvas !important;
        color: CanvasText !important;
        border: 1px solid CanvasText !important;
      }
      .code-block-decoration {
        background: Canvas !important;
        border-bottom: 1px solid CanvasText !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
      }
      :where(.model-response-text, markdown-renderer) :is(h1,h2,h3,h4)::after {
        background: CanvasText !important;
        opacity: 1 !important;
      }
    }
  `;

  if (typeof GM_addStyle !== 'undefined') {
    GM_addStyle(css);
  } else {
    const style = document.createElement('style');
    style.textContent = css;
    document.documentElement.appendChild(style);
  }

  if (DEBUG) console.log('Gemini Singularity (V5.7 Lite++) Activated.', cfg);
})();