Greasy Fork

Greasy Fork is available in English.

Gemini Singularity (V5.7 Lite++)

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

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

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

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

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

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

您需要先安装一款用户脚本管理器扩展,例如 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);
})();