有无浏览器插件可以显示mihomo分流的当前网页的分组呢?

  • 加上了实时反色
  • 双击切换左右停靠
// ==UserScript==
// @name         Clash Connection Monitor
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  优雅地显示当前网页的Clash连接信息
// @author       Your name
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @icon         https://cdn.jsdelivr.net/gh/Dreamacro/clash/docs/logo.png
// ==/UserScript==

(function () {
  ("use strict");

  // Clash API 配置
  const CLASH_API = {
    BASE_URL: "http://127.0.0.1:7890",
    SECRET: "修改为你的密码或者置空",
  };

  // 在 CLASH_API 配置后添加
  const PREFERENCES = {
    position: 'right', // 'left' 或 'right'
  };

  // 动态样式
  const style = document.createElement("style");
  style.textContent = `
    #clash-monitor {
        position: fixed;
        bottom: 20px;
        ${PREFERENCES.position}: 20px;
        z-index: 10000;
        display: flex;
        flex-direction: column-reverse;
        align-items: ${PREFERENCES.position === 'right' ? 'flex-end' : 'flex-start'};
        gap: 8px;
    }

    #status-dot {
        width: 12px;
        height: 12px;
        border-radius: 50%;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        background-color: #95a5a6;
        cursor: pointer;
        transition: transform 0.2s ease, box-shadow 0.2s ease;
    }

    #status-dot:hover {
        transform: scale(1.2);
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    }

    #connection-details {
        max-height: 0;
        opacity: 0;
        overflow: hidden;
        padding: 0;
        border-radius: 8px;
        font-size: 12px;
        line-height: 1.5;
        pointer-events: none;
        white-space: nowrap;
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        transition: all 0.3s ease;
    }

    #clash-monitor:hover #connection-details {
        max-height: 200px;
        opacity: 1;
        padding: 10px;
        pointer-events: auto;
    }

    .detail-item {
        display: flex;
        justify-content: space-between;
        gap: 16px;
        margin: 4px 0;
    }

    .detail-item span {
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
    }

    #status-dot:active {
        transform: scale(0.9);
    }
  `;
  document.head.appendChild(style);

  // 创建监视器元素
  const monitor = document.createElement("div");
  monitor.id = "clash-monitor";
  monitor.innerHTML = `
    <div id="status-dot"></div>
    <div id="connection-details">
    <code>
      <div class="detail-item">
        <span>链路:</span>
        <span id="proxy-chain">-</span>
      </div>
      <div class="detail-item">
        <span>规则:</span>
        <span id="rule-match">-</span>
      </div>
      <div class="detail-item">
        <span>上传:</span>
        <span id="upload-speed">-</span>
      </div>
      <div class="detail-item">
        <span>下载:</span>
        <span id="download-speed">-</span>
      </div>
    </code>
    </div>
  `;
  document.body.appendChild(monitor);

  // 格式化字节数
  function formatBytes(bytes) {
    if (bytes === 0 || !bytes) return "0 B";
    const k = 1024;
    const sizes = ["B", "KB", "MB", "GB"];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
  }

  // 更新连接信息
  function updateConnectionInfo() {
    GM_xmlhttpRequest({
      method: "GET",
      url: `${CLASH_API.BASE_URL}/connections`,
      headers: {
        Authorization: `Bearer ${CLASH_API.SECRET}`,
      },
      onload: function (response) {
        try {
          const data = JSON.parse(response.responseText);
          const connections = data.connections;
          const currentHost = window.location.hostname;
          const currentConn = connections.find(
            (conn) => conn.metadata.host === currentHost
          );

          const statusDot = document.getElementById("status-dot");
          const proxyChain = document.getElementById("proxy-chain");
          const ruleMatch = document.getElementById("rule-match");
          const uploadSpeed = document.getElementById("upload-speed");
          const downloadSpeed = document.getElementById("download-speed");

          if (currentConn) {
            const isProxy = !currentConn.chains.includes("DIRECT");
            statusDot.style.backgroundColor = isProxy
              ? "#3498db" // 代理:蓝色
              : "#2ecc71"; // 直连:绿色

            proxyChain.textContent = currentConn.chains.join(" → ");
            //ruleMatch.textContent = currentConn.rule || "未知";
            ruleMatch.textContent = currentConn.rulePayload ? currentConn.rulePayload + " → " + currentConn.rule : currentConn.rule;
            uploadSpeed.textContent = formatBytes(currentConn.upload);
            downloadSpeed.textContent = formatBytes(currentConn.download);
          } else {
            statusDot.style.backgroundColor = "#95a5a6"; // 断开:灰色
            proxyChain.textContent = "-";
            ruleMatch.textContent = "-";
            uploadSpeed.textContent = "-";
            downloadSpeed.textContent = "-";
          }
        } catch (error) {
          console.error("解析连接信息失败:", error);
        }
      },
      onerror: function () {
        console.error("Clash API 请求失败,请检查网络或 API 配置。");
      },
    });
  }

  // 初始化并设置定时更新
  updateConnectionInfo();
  setInterval(updateConnectionInfo, 5000);

  // 监听页面可见性变化
  document.addEventListener("visibilitychange", () => {
    if (!document.hidden) updateConnectionInfo();
  });

  // 在 CLASH_API 配置后添加检测函数
  function getBackgroundColor(element) {
    let bg = window.getComputedStyle(element).backgroundColor;
    while (bg === "rgba(0, 0, 0, 0)" && element.parentElement) {
      element = element.parentElement;
      bg = window.getComputedStyle(element).backgroundColor;
    }
    return bg === "rgba(0, 0, 0, 0)" ? "rgb(255, 255, 255)" : bg;
  }

  function isLightColor(r, g, b) {
    // 使用 YIQ 算法计算亮度
    return (r * 299 + g * 147 + b * 114) / 1000 > 128;
  }

  function getRGBValues(color) {
    const match = color.match(/\d+/g);
    return match ? match.map(Number) : [255, 255, 255];
  }

  function updateTheme() {
    const bgColor = getBackgroundColor(document.body);
    const [r, g, b] = getRGBValues(bgColor);
    const isLight = isLightColor(r, g, b);
    
    const details = document.getElementById('connection-details');
    if (!details) return;

    if (isLight) {
      details.style.background = 'rgba(255, 255, 255, 0.98)';
      details.style.color = '#2c3e50';
      details.style.borderColor = 'rgba(0, 0, 0, 0.15)';
      details.style.boxShadow = '0 2px 12px rgba(0, 0, 0, 0.15)';
    } else {
      details.style.background = 'rgba(28, 28, 30, 0.98)';
      details.style.color = '#ffffff';
      details.style.borderColor = 'rgba(255, 255, 255, 0.2)';
      details.style.boxShadow = '0 4px 16px rgba(0, 0, 0, 0.4)';
    }
  }

  // 在 document.body.appendChild(monitor) 后添加:
  updateTheme();

  // 添加 MutationObserver 监听背景色变化
  const observer = new MutationObserver(updateTheme);
  observer.observe(document.body, {
      attributes: true,
      childList: true,
      subtree: true
  });

  // 监听页面主题变化
  window.matchMedia('(prefers-color-scheme: dark)').addListener(updateTheme);

  // 添加点击切换位置的功能
  document.getElementById('status-dot').addEventListener('dblclick', function(e) {
    e.preventDefault();
    PREFERENCES.position = PREFERENCES.position === 'right' ? 'left' : 'right';
    const monitor = document.getElementById('clash-monitor');
    monitor.style[PREFERENCES.position === 'right' ? 'left' : 'right'] = '';
    monitor.style[PREFERENCES.position] = '20px';
    monitor.style.alignItems = PREFERENCES.position === 'right' ? 'flex-end' : 'flex-start';
    
    // 保存设置到 localStorage
    localStorage.setItem('clash-monitor-position', PREFERENCES.position);
  });

  // 在初始化时读取保存的位置设置
  const savedPosition = localStorage.getItem('clash-monitor-position');
  if (savedPosition) {
    PREFERENCES.position = savedPosition;
  }
})();
3 个赞

感谢大佬!平时暗色用的少,欠考虑了 :see_no_evil:

新增双击切换停靠位置

头像穹吗

对,哈哈

佬 穹是sora不是sola

这我还真不知道,不过我的这个sola是另一个动漫

缘之空 上架Steam了

之前在b站刷到过,不过好像风评不咋好呢,说剧情不行

围观支持~

使用的时候控制台遇到报错 This document requires 'TrustedHTML' assignment.


问了问claude,改动了一下 创建监视器元素 的地方,如下:

    // 创建监视器元素
    const monitor = document.createElement("div");
    monitor.id = "clash-monitor";

    // 创建状态点
    const statusDot = document.createElement("div");
    statusDot.id = "status-dot";
    monitor.appendChild(statusDot);

    // 创建连接详情容器
    const connectionDetails = document.createElement("div");
    connectionDetails.id = "connection-details";

    // 创建代码块
    const codeBlock = document.createElement("code");

    // 创建详情项
    const details = [
        { label: "链路", id: "proxy-chain" },
        { label: "规则", id: "rule-match" },
        { label: "上传", id: "upload-speed" },
        { label: "下载", id: "download-speed" }
    ];

    details.forEach(detail => {
        const detailItem = document.createElement("div");
        detailItem.className = "detail-item";

        const labelSpan = document.createElement("span");
        labelSpan.textContent = detail.label + ":";

        const valueSpan = document.createElement("span");
        valueSpan.id = detail.id;
        valueSpan.textContent = "-";

        detailItem.appendChild(labelSpan);
        detailItem.appendChild(valueSpan);
        codeBlock.appendChild(detailItem);
    });

    connectionDetails.appendChild(codeBlock);
    monitor.appendChild(connectionDetails);
    document.body.appendChild(monitor);
原代码:
// 创建监视器元素
  const monitor = document.createElement("div");
  monitor.id = "clash-monitor";
  monitor.innerHTML = `
    <div id="status-dot"></div>
    <div id="connection-details">
    <code>
      <div class="detail-item">
        <span>链路:</span>
        <span id="proxy-chain">-</span>
      </div>
      <div class="detail-item">
        <span>规则:</span>
        <span id="rule-match">-</span>
      </div>
      <div class="detail-item">
        <span>上传:</span>
        <span id="upload-speed">-</span>
      </div>
      <div class="detail-item">
        <span>下载:</span>
        <span id="download-speed">-</span>
      </div>
    </code>
    </div>
  `;
  document.body.appendChild(monitor);

youtube可以正常使用

1 个赞

看到大佬们有新回复,我就知道又有新更新了

可以在开头加一个
// @connect 127.0.0.1

默认跨域访问localhost

1 个赞

又更新了一点点,全靠GPT帮忙。

  • 现在有四种状态指示
    • 无连接 ‘#F44336’; // 红色
    • 直连 (DIRECT) ‘#4CAF50’; // 绿色
    • 命中规则 ‘#2196F3’; // 蓝色
    • 未匹配规则 (Match) ‘#FFEB3B’; // 黄色
  • 信息框为毛玻璃
  • 信息框理论上不再受到网页自定义code样式的影响
代码
// ==UserScript==
// @name         Clash Connection Monitor
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  优雅地显示当前网页的Clash连接信息
// @author       Your name
// @match        *://*/*
// @connect      127.0.0.1
// @grant        GM_xmlhttpRequest
// @icon         https://cdn.jsdelivr.net/gh/Dreamacro/clash/docs/logo.png
// ==/UserScript==

class ClashMonitor {
  constructor(config) {
    this.apiConfig = config;
    this.statusDot = null;
    this.proxyChain = null;
    this.ruleMatch = null;
    this.uploadSpeed = null;
    this.downloadSpeed = null;
    this.init();
  }

  init() {
    this.injectStyles();
    this.createUI();
    this.updateConnectionInfo();
    setInterval(() => this.updateConnectionInfo(), 5000);
    document.addEventListener('visibilitychange', () => {
      if (!document.hidden) this.updateConnectionInfo();
    });
  }

  injectStyles() {
    const style = document.createElement('style');
    style.textContent = `
        #clash-monitor {
            position: fixed;
            bottom: 20px;
            left: 20px;
            z-index: 10000;
            display: flex;
            flex-direction: column-reverse;
            align-items: flex-start;
            gap: 8px;
        }
  
        #status-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            background-color: #95a5a6;
            cursor: pointer;
            transition: transform 0.2s ease, box-shadow 0.2s ease;
        }
  
        #status-dot:hover {
            transform: scale(1.2);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }
  
        #connection-details {
            max-height: 0;
            opacity: 0;
            overflow: hidden;
            padding: 0;
            border-radius: 8px;
            font-size: 12px;
            line-height: 1.5;
            pointer-events: none;
            white-space: nowrap;
            backdrop-filter: blur(12px);
            -webkit-backdrop-filter: blur(12px);
            transition: all 0.3s ease;
        }
  
        #status-dot:hover + #connection-details {
            max-height: 200px;
            opacity: 1;
            padding: 10px;
            pointer-events: auto;
        }
  
        .detail-item {
            display: flex;
            justify-content: space-between;
            gap: 16px;
            margin: 4px 0;
        }
  
        .detail-item span {
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
        }
  
        .detail-item code {
            background-color: #ffffff00
        }
      `;
    document.head.appendChild(style);
  }

  createUI() {
    // 创建监视器元素
    const monitor = document.createElement('div');
    monitor.id = 'clash-monitor';

    // 创建状态点
    const statusDot = document.createElement('div');
    statusDot.id = 'status-dot';
    monitor.appendChild(statusDot);

    // 创建连接详情容器
    const connectionDetails = document.createElement('div');
    connectionDetails.id = 'connection-details';

    // 创建代码块
    const codeBlock = document.createElement('code');

    // 创建详情项
    const details = [
      { label: '链路', id: 'proxy-chain' },
      { label: '规则', id: 'rule-match' },
      { label: '上传', id: 'upload-speed' },
      { label: '下载', id: 'download-speed' },
    ];

    details.forEach((detail) => {
      const detailItem = document.createElement('div');
      detailItem.className = 'detail-item';

      // 创建并包裹labelSpan
      const labelSpan = document.createElement('span');
      labelSpan.textContent = detail.label + ':';
      const labelCode = document.createElement('code');
      labelCode.appendChild(labelSpan);

      // 创建并包裹valueSpan
      const valueSpan = document.createElement('span');
      valueSpan.id = detail.id;
      valueSpan.textContent = '-';
      const valueCode = document.createElement('code');
      valueCode.appendChild(valueSpan);

      detailItem.appendChild(labelCode);
      detailItem.appendChild(valueCode);

      // 直接插入到 connectionDetails 中
      connectionDetails.appendChild(detailItem);
    });
    monitor.appendChild(connectionDetails);
    document.body.appendChild(monitor);
    this.statusDot = document.getElementById('status-dot');
    this.proxyChain = document.getElementById('proxy-chain');
    this.ruleMatch = document.getElementById('rule-match');
    this.uploadSpeed = document.getElementById('upload-speed');
    this.downloadSpeed = document.getElementById('download-speed');
  }

  formatBytes(bytes) {
    if (bytes === 0 || !bytes) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  updateConnectionInfo() {
    GM_xmlhttpRequest({
      method: 'GET',
      url: `${this.apiConfig.BASE_URL}/connections`,
      headers: {
        Authorization: `Bearer ${this.apiConfig.SECRET}`,
      },
      onload: (response) => {
        try {
          const data = JSON.parse(response.responseText);
          const connections = data.connections;
          const currentHost = window.location.hostname;
          const currentConn = connections.find((conn) => conn.metadata.host === currentHost);

          if (currentConn) {
            this.statusDot.style.backgroundColor = this.getStatusColor(currentConn);
            this.proxyChain.textContent = currentConn.chains.reverse().join(' -> ') || '-';
            this.ruleMatch.textContent = currentConn.rulePayload ? `${currentConn.rule} -> ${currentConn.rulePayload}` : currentConn.rule || '-';
            this.uploadSpeed.textContent = this.formatBytes(currentConn.upload);
            this.downloadSpeed.textContent = this.formatBytes(currentConn.download);
          } else {
            this.resetUI();
          }
        } catch (error) {
          console.error('解析连接信息失败:', error);
        }
      },
      onerror: () => {
        console.error('Clash API 请求失败,请检查网络或 API 配置。');
      },
    });
  }

  getStatusColor(currentConn) {
    if (!currentConn.chains.length) return '#F44336'; // 无连接:红色
    if (currentConn.rule.includes('Match')) return '#FFEB3B'; // 匹配:黄色
    if (currentConn.chains.includes('Direct')) return '#4CAF50'; // 直连:绿色
    return '#2196F3'; // 其他:蓝色
  }

  resetUI() {
    this.statusDot.style.backgroundColor = '#95a5a6';
    this.proxyChain.textContent = '-';
    this.ruleMatch.textContent = '-';
    this.uploadSpeed.textContent = '-';
    this.downloadSpeed.textContent = '-';
  }
}

const CLASH_API_CONFIG = {
  BASE_URL: 'http://127.0.0.1:xxxx',
  SECRET: 'xxxx',
};

new ClashMonitor(CLASH_API_CONFIG);

2 个赞

可以,增加了双击切换停靠位置

// ==UserScript==
// @name         Clash Connection Monitor
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  优雅地显示当前网页的Clash连接信息
// @author       Your name
// @match        *://*/*
// @connect      127.0.0.1
// @grant        GM_xmlhttpRequest
// @icon         https://cdn.jsdelivr.net/gh/Dreamacro/clash/docs/logo.png
// ==/UserScript==

class ClashMonitor {
  constructor(config) {
    this.apiConfig = config;
    this.statusDot = null;
    this.proxyChain = null;
    this.ruleMatch = null;
    this.uploadSpeed = null;
    this.downloadSpeed = null;
    this.position = localStorage.getItem('clash-monitor-position') || 'left';
    this.init();
  }

  init() {
    this.injectStyles();
    this.createUI();
    this.updateConnectionInfo();
    setInterval(() => this.updateConnectionInfo(), 5000);
    document.addEventListener("visibilitychange", () => {
      if (!document.hidden) this.updateConnectionInfo();
    });
  }

  injectStyles() {
    const style = document.createElement("style");
    style.textContent = `
        #clash-monitor {
            position: fixed;
            bottom: 20px;
            ${this.position}: 20px;
            z-index: 10000;
            display: flex;
            flex-direction: column-reverse;
            align-items: ${this.position === 'left' ? 'flex-start' : 'flex-end'};
            gap: 8px;
            transition: all 0.3s ease;
        }

        #status-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            background-color: #95a5a6;
            cursor: pointer;
            transition: transform 0.2s ease, box-shadow 0.2s ease;
        }

        #status-dot:hover {
            transform: scale(1.2);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        }

        #connection-details {
            max-height: 0;
            opacity: 0;
            overflow: hidden;
            padding: 0;
            border-radius: 8px;
            font-size: 12px;
            line-height: 1.5;
            pointer-events: none;
            white-space: nowrap;
            backdrop-filter: blur(12px);
            -webkit-backdrop-filter: blur(12px);
            transition: all 0.3s ease;
        }

        #status-dot:hover + #connection-details {
            max-height: 200px;
            opacity: 1;
            padding: 10px;
            pointer-events: auto;
        }

        .detail-item {
            display: flex;
            justify-content: space-between;
            gap: 16px;
            margin: 4px 0;
        }

        .detail-item span {
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
        }

        .detail-item code {
            background-color: #ffffff00
        }
      `;
    document.head.appendChild(style);
  }

  createUI() {
    // 创建监视器元素
    const monitor = document.createElement("div");
    monitor.id = "clash-monitor";

    // 创建状态点
    const statusDot = document.createElement("div");
    statusDot.id = "status-dot";
    monitor.appendChild(statusDot);

    // 创建连接详情容器
    const connectionDetails = document.createElement("div");
    connectionDetails.id = "connection-details";

    // 创建代码块
    const codeBlock = document.createElement("code");

    // 创建详情项
    const details = [
      { label: "链路", id: "proxy-chain" },
      { label: "规则", id: "rule-match" },
      { label: "上传", id: "upload-speed" },
      { label: "下载", id: "download-speed" },
    ];

    details.forEach((detail) => {
      const detailItem = document.createElement("div");
      detailItem.className = "detail-item";

      // 创建并包裹labelSpan
      const labelSpan = document.createElement("span");
      labelSpan.textContent = detail.label + ":";
      const labelCode = document.createElement("code");
      labelCode.appendChild(labelSpan);

      // 创建并包裹valueSpan
      const valueSpan = document.createElement("span");
      valueSpan.id = detail.id;
      valueSpan.textContent = "-";
      const valueCode = document.createElement("code");
      valueCode.appendChild(valueSpan);

      detailItem.appendChild(labelCode);
      detailItem.appendChild(valueCode);

      // 直接插入到 connectionDetails 中
      connectionDetails.appendChild(detailItem);
    });
    monitor.appendChild(connectionDetails);

    monitor.addEventListener('dblclick', () => {
        this.position = this.position === 'left' ? 'right' : 'left';
        localStorage.setItem('clash-monitor-position', this.position);
        monitor.style[this.position === 'left' ? 'right' : 'left'] = '';
        monitor.style[this.position] = '20px';
        monitor.style.alignItems = this.position === 'left' ? 'flex-start' : 'flex-end';
    });

    document.body.appendChild(monitor);
    this.statusDot = document.getElementById("status-dot");
    this.proxyChain = document.getElementById("proxy-chain");
    this.ruleMatch = document.getElementById("rule-match");
    this.uploadSpeed = document.getElementById("upload-speed");
    this.downloadSpeed = document.getElementById("download-speed");
  }

  formatBytes(bytes) {
    if (bytes === 0 || !bytes) return "0 B";
    const k = 1024;
    const sizes = ["B", "KB", "MB", "GB"];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
  }

  updateConnectionInfo() {
    GM_xmlhttpRequest({
      method: "GET",
      url: `${this.apiConfig.BASE_URL}/connections`,
      headers: {
        Authorization: `Bearer ${this.apiConfig.SECRET}`,
      },
      onload: (response) => {
        try {
          const data = JSON.parse(response.responseText);
          const connections = data.connections;
          const currentHost = window.location.hostname;
          const currentConn = connections.find(
            (conn) => conn.metadata.host === currentHost
          );

          if (currentConn) {
            this.statusDot.style.backgroundColor =
              this.getStatusColor(currentConn);
            this.proxyChain.textContent =
              currentConn.chains.reverse().join(" -> ") || "-";
            this.ruleMatch.textContent = currentConn.rulePayload
              ? `${currentConn.rule} -> ${currentConn.rulePayload}`
              : currentConn.rule || "-";
            this.uploadSpeed.textContent = this.formatBytes(currentConn.upload);
            this.downloadSpeed.textContent = this.formatBytes(
              currentConn.download
            );
          } else {
            this.resetUI();
          }
        } catch (error) {
          console.error("解析连接信息失败:", error);
        }
      },
      onerror: () => {
        console.error("Clash API 请求失败,请检查网络或 API 配置。");
      },
    });
  }

  getStatusColor(currentConn) {
    if (!currentConn.chains.length) return "#F44336"; // 无连接:红色
    if (currentConn.rule.includes("Match")) return "#FFEB3B"; // 匹配:黄色
    if (currentConn.chains.includes("Direct")) return "#4CAF50"; // 直连:绿色
    return "#2196F3"; // 其他:蓝色
  }

  resetUI() {
    this.statusDot.style.backgroundColor = "#95a5a6";
    this.proxyChain.textContent = "-";
    this.ruleMatch.textContent = "-";
    this.uploadSpeed.textContent = "-";
    this.downloadSpeed.textContent = "-";
  }
}

const CLASH_API_CONFIG = {
  BASE_URL: "http://127.0.0.1:2021",
  SECRET: "xxxx",
};

new ClashMonitor(CLASH_API_CONFIG);

4 个赞

等大佬们的终极版

大佬,有没有精力把这个项目放在github上
功能聚合,位置随意调整,颜色随意调整,面板主题可选,面板内容展示条目可选,之类的。
或者再有精力,也弄个singbox,v2ray,之类的接口。
我看大家都对这个项目感兴趣啊,到时候我改改标题,让大家给你加star

这个是基于 clash API 的。暂时先维护到这吧,这方面的不太想公开,可以点我头像项目点点 star

2 个赞

此话题已在最后回复的 30 天后被自动关闭。不再允许新回复。