ccswitch-shared-ui.local

shared ui code

Этот скрипт недоступен для установки пользователем. Он является библиотекой, которая подключается к другим скриптам мета-ключом // @require https://update.greasyfork.org/scripts/582598/1850862/ccswitch-shared-uilocal.js

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// Shared local development helpers for CC Switch import userscripts.
// Load this file before any local business entry via Tampermonkey @require.
// @name         ccswitch-shared-ui.local
// @version      0.0.1
// @author       irisWirisW (https://github.com/irisWirisW)
// @license      AGPL-3.0-or-later
(() => {
  "use strict";

  if (window.CCSwitchSharedUI) return;

  const DEFAULT_APP = "codex";
  const SHARED_DIALOG_STYLE_ID = "ccs-shared-dialog-style";
  const SHARED_DIALOG_CSS = `
    .ccs-shared-modal {
      --ccs-overlay: rgba(2, 6, 23, 0.6);
      --ccs-panel: rgba(15, 23, 42, 0.86);
      --ccs-panel-strong: rgba(30, 41, 59, 0.78);
      --ccs-panel-border: rgba(148, 163, 184, 0.22);
      --ccs-text: #e5eefb;
      --ccs-muted: #94a3b8;
      --ccs-input-bg: rgba(15, 23, 42, 0.72);
      --ccs-input-border: rgba(148, 163, 184, 0.26);
      --ccs-primary: #38bdf8;
      --ccs-primary-strong: #0284c7;
      --ccs-focus: rgba(56, 189, 248, 0.18);
      position: fixed;
      inset: 0;
      background: var(--ccs-overlay);
      display: none;
      align-items: center;
      justify-content: center;
      z-index: 99999;
      padding: 18px;
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      color-scheme: dark;
    }
    .ccs-shared-modal.open {
      display: flex;
    }
    .ccs-shared-panel {
      width: min(600px, 100%);
      max-height: calc(100vh - 36px);
      overflow: auto;
      border-radius: 18px;
      background:
        radial-gradient(circle at 16% 8%, rgba(56, 189, 248, 0.18), transparent 30%),
        radial-gradient(circle at 82% 0%, rgba(45, 212, 191, 0.12), transparent 26%),
        linear-gradient(135deg, var(--ccs-panel-strong), var(--ccs-panel));
      border: 1px solid var(--ccs-panel-border);
      box-shadow:
        0 24px 70px rgba(0, 0, 0, 0.42),
        0 1px 0 rgba(255, 255, 255, 0.12) inset;
      color: var(--ccs-text);
      padding: 18px;
      font-size: 13px;
      backdrop-filter: blur(22px) saturate(150%);
      -webkit-backdrop-filter: blur(22px) saturate(150%);
    }
    .ccs-shared-head {
      display: flex;
      align-items: flex-start;
      justify-content: space-between;
      gap: 16px;
      margin-bottom: 14px;
    }
    .ccs-shared-kicker {
      width: fit-content;
      border-radius: 999px;
      border: 1px solid rgba(56, 189, 248, 0.24);
      background: rgba(8, 47, 73, 0.46);
      color: #7dd3fc;
      font-size: 11px;
      font-weight: 700;
      line-height: 1;
      padding: 5px 8px;
      margin-bottom: 8px;
    }
    .ccs-shared-close {
      width: 32px;
      height: 32px;
      flex: 0 0 32px;
      border-radius: 999px;
      border: 1px solid rgba(148, 163, 184, 0.24);
      background: rgba(15, 23, 42, 0.48);
      color: #cbd5e1;
      font-size: 20px;
      line-height: 1;
      cursor: pointer;
      box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset;
    }
    .ccs-shared-title {
      font-size: 20px;
      font-weight: 700;
      line-height: 1.25;
      color: var(--ccs-text);
    }
    .ccs-shared-message {
      color: #cbd5e1;
      font-size: 12px;
      line-height: 1.5;
      margin: 0;
      padding: 10px 12px;
      border: 1px solid rgba(148, 163, 184, 0.16);
      border-radius: 12px;
      background: rgba(15, 23, 42, 0.46);
    }
    .ccs-shared-hint {
      margin-top: 7px;
      font-size: 12px;
      color: #fde68a;
      line-height: 1.4;
      display: none;
      padding: 8px 10px;
      border-radius: 10px;
      background: rgba(120, 53, 15, 0.24);
      border: 1px solid rgba(245, 158, 11, 0.22);
    }
    .ccs-shared-panel label {
      display: block;
      color: #cbd5e1;
      font-size: 12px;
      font-weight: 700;
      margin: 0 0 6px;
    }
    .ccs-shared-overview {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(220px, 1fr);
      gap: 12px 18px;
      align-items: stretch;
      margin-bottom: 14px;
    }
    .ccs-shared-primary-fields,
    .ccs-shared-notes {
      min-width: 0;
      display: grid;
      gap: 12px;
      align-content: start;
    }
    .ccs-shared-grid {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      gap: 12px;
    }
    .ccs-shared-field {
      min-width: 0;
    }
    .ccs-shared-field-wide {
      grid-column: 1 / -1;
    }
    .ccs-shared-panel input,
    .ccs-shared-panel select {
      width: 100%;
      display: block;
      box-sizing: border-box;
      min-height: 38px;
      border-radius: 11px;
      border: 1px solid var(--ccs-input-border);
      background-color: var(--ccs-input-bg);
      color: var(--ccs-text);
      padding: 8px 11px;
      font-size: 13px;
      outline: none;
      box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset;
      transition:
        border-color 140ms ease,
        box-shadow 140ms ease,
        background 140ms ease;
    }
    .ccs-shared-panel input:focus,
    .ccs-shared-panel select:focus {
      border-color: rgba(56, 189, 248, 0.72);
      background-color: rgba(15, 23, 42, 0.9);
      box-shadow:
        0 0 0 4px var(--ccs-focus),
        0 1px 0 rgba(255, 255, 255, 0.1) inset;
    }
    .ccs-shared-panel select {
      appearance: none;
      -webkit-appearance: none;
      padding-right: 34px;
      background-image:
        linear-gradient(45deg, transparent 50%, rgba(203, 213, 225, 0.86) 50%),
        linear-gradient(135deg, rgba(203, 213, 225, 0.86) 50%, transparent 50%);
      background-position:
        calc(100% - 18px) calc(50% - 1px),
        calc(100% - 13px) calc(50% - 1px);
      background-size: 6px 6px, 6px 6px;
      background-repeat: no-repeat;
    }
    .ccs-shared-panel select:focus {
      background-image:
        linear-gradient(45deg, transparent 50%, rgba(224, 242, 254, 0.96) 50%),
        linear-gradient(135deg, rgba(224, 242, 254, 0.96) 50%, transparent 50%);
    }
    .ccs-shared-panel option {
      background: #0f172a;
      color: var(--ccs-text);
    }
    .ccs-shared-actions {
      margin-top: 16px;
      display: flex;
      justify-content: flex-end;
      gap: 8px;
      flex-wrap: wrap;
    }
    .ccs-shared-actions button {
      min-height: 34px;
      border-radius: 999px;
      border: 1px solid rgba(148, 163, 184, 0.24);
      background: rgba(15, 23, 42, 0.52);
      color: #cbd5e1;
      font-size: 12px;
      font-weight: 700;
      padding: 7px 13px;
      cursor: pointer;
      box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset;
    }
    .ccs-shared-actions .ccs-shared-primary {
      background: linear-gradient(135deg, var(--ccs-primary), var(--ccs-primary-strong));
      border-color: rgba(56, 189, 248, 0.3);
      color: #f8fafc;
      box-shadow:
        0 12px 26px rgba(14, 165, 233, 0.22),
        0 1px 0 rgba(255, 255, 255, 0.18) inset;
    }
    .ccs-shared-actions .ccs-shared-primary:disabled {
      opacity: 0.6;
      cursor: not-allowed;
    }
    .ccs-shared-close:hover,
    .ccs-shared-actions button:hover {
      filter: brightness(1.08);
    }
    @media (max-width: 560px) {
      .ccs-shared-overview,
      .ccs-shared-grid {
        grid-template-columns: 1fr;
      }
      .ccs-shared-panel {
        border-radius: 16px;
        padding: 15px;
      }
      .ccs-shared-actions button {
        flex: 1 1 auto;
      }
    }
  `;

  function injectStyleOnce(styleId, cssText) {
    const existing = document.getElementById(styleId);
    if (existing) return existing;

    const style = document.createElement("style");
    style.id = styleId;
    style.textContent = cssText;
    document.head.appendChild(style);
    return style;
  }

  function injectSharedDialogStyles() {
    return injectStyleOnce(SHARED_DIALOG_STYLE_ID, SHARED_DIALOG_CSS);
  }

  function inferName(endpoint) {
    try {
      return new URL(endpoint).host;
    } catch {
      return "custom";
    }
  }

  function getDefaultNameByApp(app, endpoint, defaultApp = DEFAULT_APP) {
    if ((app || defaultApp) === "codex") return "custom";
    return inferName(endpoint);
  }

  function updateCodexNameHint(target, options) {
    if (!target) return;

    const {
      app,
      name,
      defaultApp = DEFAULT_APP,
      prefixText = "",
      okText = "当前已设置为 custom。",
      warnText = "当前不是 custom,可能导致 thread 出错。",
    } = options || {};

    if ((app || defaultApp) !== "codex") {
      target.style.display = "none";
      target.textContent = "";
      return;
    }

    const normalizedName = (name || "").trim();
    const statusText = normalizedName === "custom" ? okText : warnText;
    target.style.display = "block";
    target.textContent = `${prefixText}${statusText}`;
  }

  function bindAutoSelect(input) {
    if (!input) return;

    const selectAll = () => {
      input.focus();
      input.select();
    };

    input.addEventListener("focus", () => setTimeout(selectAll, 0));
    input.addEventListener("click", selectAll);
    input.addEventListener("mouseup", (event) => event.preventDefault());
  }

  function buildDialogShell(options) {
    const {
      panelClass = "",
      titleId,
      kicker,
      title,
      primaryHtml = "",
      notesHtml = "",
      gridHtml = "",
      actionsHtml = "",
    } = options || {};

    return `
      <div class="${panelClass} ccs-shared-panel" role="dialog" aria-modal="true" aria-labelledby="${titleId}">
        <div class="ccs-shared-head">
          <div>
            <div class="ccs-shared-kicker">${kicker}</div>
            <div class="ccs-shared-title" id="${titleId}">${title}</div>
          </div>
          <button type="button" class="ccs-shared-close" aria-label="关闭">×</button>
        </div>
        <div class="ccs-shared-overview">
          <div class="ccs-shared-primary-fields">${primaryHtml}</div>
          <div class="ccs-shared-notes">${notesHtml}</div>
        </div>
        <div class="ccs-shared-grid">${gridHtml}</div>
        <div class="ccs-shared-actions">${actionsHtml}</div>
      </div>
    `;
  }

  window.CCSwitchSharedUI = {
    DEFAULT_APP,
    injectStyleOnce,
    injectSharedDialogStyles,
    inferName,
    getDefaultNameByApp,
    updateCodexNameHint,
    bindAutoSelect,
    buildDialogShell,
  };
})();