CSS Extractor for Lanhu

从蓝湖网站上提取CSS代码并打印到控制台

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         CSS Extractor for Lanhu
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  从蓝湖网站上提取CSS代码并打印到控制台
// @author       TikeAI
// @match        https://lanhuapp.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=lanhuapp.com
// @license      MIT
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  // 定义抽屉元素类型
  /**
   * @typedef {HTMLDivElement & { disconnect: VoidFunction }} DrawerElement
   */

  // 全局引用对象,用于存储当前抽屉元素和CSS内容
  let ref = {
    current: null,
    css: "",
  };

  /**
   * 观察抽屉元素变化的函数
   * @param {DrawerElement} el - 抽屉元素
   */
  function observeDrawer(el) {
    // 如果存在之前的抽屉元素,断开其观察器连接并清空CSS
    if (ref.current) {
      ref.current.disconnect && ref.current.disconnect();
      ref.css = "";
    }
    ref.current = el;

    // 使用防抖处理观察到的变化
    let obsFn = debounce(
      async () => {
        // 查找代码详情元素
        let detailbox = el.querySelector(".annotation_item.code_detail");
        let codebox = detailbox?.querySelector(".code_box");

        let anchor = null;
        let css = "";
        // 获取原本的css样式
        {
          if (codebox) {
            // 如果存在代码框,直接获取其中的CSS内容
            anchor = detailbox;
            css = codebox.textContent;
          } else {
            // 否则从标注项中获取尺寸信息
            let itembox = last(
              Array.from(
                el.querySelectorAll(".annotation_container > .annotation_item")
              )
            );
            anchor = itembox;

            // 查找包含"大小"的列表项
            let list = el.querySelectorAll(
              ".annotation_container > .annotation_item li"
            );
            let sizebox = Array.from(list).find((li) => {
              return trim(li.textContent).startsWith("大小");
            });

            if (sizebox) {
              // 提取宽度和高度信息
              let sizeElements = Array.from(
                sizebox.querySelectorAll(".item_two")
              );
              if (sizeElements.length >= 2) {
                let width = trim(sizeElements[0].textContent);
                let height = trim(sizeElements[1].textContent);
                css = `width: ${width}; height: ${height};`;
              }
            }
          }
          // 将CSS包装在.app选择器中
          css = `.app { ${css} }`;
        }

        // 如果CSS内容发生变化
        if (ref.css !== css) {
          ref.css = css;

          try {
            // 直接打印CSS到控制台
            console.log("%c[CSS提取]", "color:#3799a8;", css);

            // 在页面上显示提取的CSS
            showCssPopup(css);
          } catch (e) {
            console.warn("%c[error]", "color:red;", e);
          }
        }
      },
      100,
      { leading: false, trailing: true }
    );

    // 创建并配置MutationObserver来观察元素变化
    let obs = new MutationObserver(obsFn);
    obs.observe(el, {
      characterData: true,
      subtree: true,
      childList: true,
    });
    // 添加断开观察器的方法
    el.disconnect = () => {
      obs.disconnect();
    };
  }

  /**
   * 格式化CSS代码使其更易读
   * @param {string} css - 原始CSS代码
   * @returns {string} - 格式化后的CSS代码
   */
  function formatCss(css) {
    // 移除多余空格和换行
    let formatted = css.replace(/\s+/g, " ");

    // 替换分号后添加换行
    formatted = formatted.replace(/;\s*/g, ";\n  ");

    // 替换左大括号后添加换行
    formatted = formatted.replace(/{\s*/g, "{\n  ");

    // 替换右大括号前添加换行
    formatted = formatted.replace(/\s*}/g, "\n}");

    // 处理嵌套选择器
    formatted = formatted.replace(/}\s*\./g, "}\n\n.");

    return formatted;
  }

  /**
   * 将CSS属性转换为Tailwind CSS格式
   * @param {string} css - 原始CSS代码
   * @returns {string} - 转换后的Tailwind CSS代码
   */
  function convertToTailwind(css) {
    // 提取CSS属性
    const properties = {};
    const regex = /(\w+-?\w*?):\s*([^;]+);/g;
    let match;

    while ((match = regex.exec(css)) !== null) {
      const property = match[1].trim();
      const value = match[2].trim();
      properties[property] = value;
    }

    // 转换为Tailwind类
    const tailwindClasses = [];
    // 处理背景色
    if (properties.background) {
      tailwindClasses.push(`bg-[${properties.background}]`);
    }

    // 处理圆角
    if (properties["border-radius"]) {
      tailwindClasses.push(`rounded-[${properties["border-radius"]}]`);
    }
    // 只有在没有字体大小时才处理宽高
    if (!properties["font-size"]) {
      // 处理宽度
      if (properties.width) {
        tailwindClasses.push(`w-[${properties.width}]`);
      }

      // 处理高度
      if (properties.height) {
        tailwindClasses.push(`h-[${properties.height}]`);
      }
    }

    // 处理字体系列
    // if (properties["font-family"]) {
    //   tailwindClasses.push(`font-[${properties["font-family"]}]`);
    // }

    // 处理字体粗细
    if (properties["font-weight"]) {
      const weightMap = {
        100: "thin",
        200: "extralight",
        300: "light",
        400: "normal",
        500: "medium",
        600: "semibold",
        700: "bold",
        800: "extrabold",
        900: "black",
      };
      const weight = weightMap[properties["font-weight"]];
      tailwindClasses.push(`font-${weight}`);
    }

    // 处理字体大小
    if (properties["font-size"]) {
      tailwindClasses.push(`text-[${properties["font-size"]}]`);
    }

    // 处理颜色
    if (properties.color) {
      tailwindClasses.push(`text-[${properties.color}]`);
    }

    // 处理行高
    // if (properties["line-height"]) {
    //   tailwindClasses.push(`leading-[${properties["line-height"]}]`);
    // }

    // 处理字间距
    // if (properties["letter-spacing"]) {
    //   tailwindClasses.push(`tracking-[${properties["letter-spacing"]}]`);
    // }

    // 处理文本对齐
    // if (properties["text-align"]) {
    //   tailwindClasses.push(`text-${properties["text-align"]}`);
    // }

    // 处理字体样式
    // if (properties["font-style"]) {
    //   if (properties["font-style"] === "italic") {
    //     tailwindClasses.push("italic");
    //   } else if (properties["font-style"] === "normal") {
    //     tailwindClasses.push("not-italic");
    //   }
    // }

    // 过滤掉空字符串并以换行方式返回
    return tailwindClasses.filter((c) => c).join("\n");
  }

  /**
   * 在页面上显示CSS弹窗
   * @param {string} css - 提取的CSS代码
   */
  function showCssPopup(css) {
    // 格式化CSS代码
    const formattedCss = formatCss(css);

    // 转换为Tailwind CSS
    const tailwindCss = convertToTailwind(css);

    // 检查是否已存在弹窗
    let existingPopup = document.getElementById("css-extractor-popup");
    if (existingPopup) {
      existingPopup.querySelector(".css-content").textContent = formattedCss;
      existingPopup.querySelector(".tailwind-content").textContent =
        tailwindCss;
      return;
    }

    // 添加动画和全局样式
    const styleElement = document.createElement("style");
    styleElement.textContent = `
      @keyframes fadeIn {
        from { opacity: 0; transform: translateY(-10px); }
        to { opacity: 1; transform: translateY(0); }
      }
      
      @keyframes slideIn {
        from { transform: translateX(10px); opacity: 0; }
        to { transform: translateX(0); opacity: 1; }
      }
      
      .tab-hover {
        transition: all 0.2s ease;
      }
      
      .tab-hover:hover {
        background-color: rgba(74, 144, 226, 0.1);
      }
    `;
    document.head.appendChild(styleElement);

    // 创建弹窗容器
    const popup = document.createElement("div");
    popup.id = "css-extractor-popup";
    popup.style.cssText = `
      position: fixed;
      top: 49px;
      right: 302px;
      background: white;
      border: none;
      border-radius: 12px;
      padding: 0;
      width: 380px;
      overflow: hidden;
      z-index: 9999;
      box-shadow: 0 8px 24px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.08);
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
      animation: fadeIn 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    `;

    // 创建标题栏
    const titleBar = document.createElement("div");
    titleBar.style.cssText = `
      background: linear-gradient(135deg, #4a90e2, #5a6acf);
      color: white;
      padding: 12px 18px;
      font-weight: 600;
      font-size: 15px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      cursor: move;
      user-select: none;
      border-top-left-radius: 12px;
      border-top-right-radius: 12px;
      box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    `;
    titleBar.innerHTML =
      '<span style="display: flex; align-items: center;"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 8px;"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17.5" y1="15" x2="9" y2="15"></line></svg>CSS提取器</span>';
    titleBar.className = "css-extractor-titlebar";

    // 创建按钮容器
    const buttonContainer = document.createElement("div");
    buttonContainer.style.cssText = `
      display: flex;
      gap: 8px;
    `;

    // 创建回到原位按钮
    const resetPositionBtn = document.createElement("button");
    resetPositionBtn.innerHTML =
      '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path></svg>';
    resetPositionBtn.style.cssText = `
      border: none;
      background: rgba(255,255,255,0.25);
      color: white;
      border-radius: 6px;
      padding: 5px;
      cursor: pointer;
      font-size: 13px;
      transition: all 0.2s;
      display: flex;
      align-items: center;
      justify-content: center;
    `;
    resetPositionBtn.title = "回到原位置";
    resetPositionBtn.onmouseover = () => {
      resetPositionBtn.style.backgroundColor = "rgba(255,255,255,0.4)";
      resetPositionBtn.style.transform = "scale(1.05)";
    };
    resetPositionBtn.onmouseout = () => {
      resetPositionBtn.style.backgroundColor = "rgba(255,255,255,0.25)";
      resetPositionBtn.style.transform = "scale(1)";
    };
    resetPositionBtn.onclick = (e) => {
      e.stopPropagation();
      popup.style.transition = "all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)";
      popup.style.top = "49px";
      popup.style.right = "302px";
      popup.style.left = "auto";
      popup.style.bottom = "auto";

      // 添加一个轻微的动画效果
      popup.style.transform = "scale(1.03)";
      setTimeout(() => {
        popup.style.transform = "scale(1)";
      }, 300);
    };

    // 创建关闭按钮
    const closeBtn = document.createElement("button");
    closeBtn.innerHTML =
      '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
    closeBtn.style.cssText = `
      border: none;
      background: rgba(255,255,255,0.25);
      color: white;
      border-radius: 6px;
      padding: 5px;
      cursor: pointer;
      font-size: 13px;
      transition: all 0.2s;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 26px;
      height: 26px;
    `;
    closeBtn.onmouseover = () => {
      closeBtn.style.background = "rgba(255,255,255,0.4)";
      closeBtn.style.transform = "translateY(-1px)";
    };
    closeBtn.onmouseout = () => {
      closeBtn.style.background = "rgba(255,255,255,0.25)";
      closeBtn.style.transform = "translateY(0)";
    };
    closeBtn.onclick = () => {
      document.body.removeChild(popup);
    };

    // 将按钮添加到按钮容器
    buttonContainer.appendChild(resetPositionBtn);
    buttonContainer.appendChild(closeBtn);

    // 将按钮容器添加到标题栏
    titleBar.appendChild(buttonContainer);

    // 创建内容容器
    const tabContainer = document.createElement("div");
    tabContainer.style.cssText = `
      display: flex;
      border-bottom: 1px solid rgba(0,0,0,0.08);
      background: #f8f9fa;
      padding: 0 10px;
    `;

    // 创建CSS标签
    const cssTab = document.createElement("div");
    cssTab.textContent = "CSS";
    cssTab.className = "css-tab tab-hover";
    cssTab.style.cssText = `
      padding: 12px 18px;
      cursor: pointer;
      border-bottom: 2px solid transparent;
      font-weight: 500;
      color: #666;
      font-size: 14px;
      transition: all 0.2s ease;
      border-radius: 6px 6px 0 0;
      margin: 6px 4px 0 4px;
    `;

    // 创建Tailwind标签
    const tailwindTab = document.createElement("div");
    tailwindTab.textContent = "Tailwind";
    tailwindTab.className = "tailwind-tab active-tab tab-hover";
    tailwindTab.style.cssText = `
      padding: 12px 18px;
      cursor: pointer;
      border-bottom: 2px solid #4a90e2;
      font-weight: 600;
      color: #4a90e2;
      font-size: 14px;
      transition: all 0.2s ease;
      background-color: rgba(74, 144, 226, 0.08);
      border-radius: 6px 6px 0 0;
      margin: 6px 4px 0 4px;
    `;

    // 添加标签到标签容器
    tabContainer.appendChild(cssTab);
    tabContainer.appendChild(tailwindTab);

    // 创建内容容器
    const contentContainer = document.createElement("div");
    contentContainer.style.cssText = `
      padding: 20px;
      max-height: none;
      overflow: auto;
      background: #f8f9fa;
      border-radius: 0 0 12px 12px;
    `;

    // 创建CSS内容区域
    const cssContent = document.createElement("pre");
    cssContent.className = "css-content";
    cssContent.style.cssText = `
      margin: 0;
      margin-bottom: 10px;
      white-space: pre-wrap;
      word-break: break-all;
      font-family: 'SF Mono', Consolas, Monaco, 'Andale Mono', monospace;
      font-size: 14px;
      color: #333;
      line-height: 1.6;
      display: none;
      padding: 16px;
      background-color: #ffffff;
      border-radius: 8px;
      animation: fadeIn 0.3s ease-in-out;
      box-shadow: 0 1px 3px rgba(0,0,0,0.05);
      border: 1px solid rgba(0,0,0,0.05);
      cursor: pointer;
    `;
    cssContent.textContent = formattedCss;

    // 添加双击复制功能
    cssContent.ondblclick = (event) => {
      // 阻止默认行为,防止页面滚动
      event.preventDefault();

      // 获取内容并替换换行符为空格
      let contentToCopy = cssContent.textContent;
      contentToCopy = contentToCopy.replace(/\n/g, " ");

      // 复制到剪贴板
      navigator.clipboard.writeText(contentToCopy).then(
        () => {
          // 复制成功提示 - 添加临时样式变化
          const originalBackground = cssContent.style.backgroundColor;
          const originalColor = cssContent.style.color;

          cssContent.style.backgroundColor = "rgba(16, 185, 129, 0.1)";
          cssContent.style.color = "rgba(16, 185, 129, 1)";

          setTimeout(() => {
            cssContent.style.backgroundColor = originalBackground;
            cssContent.style.color = originalColor;
          }, 1000);
        },
        (err) => {
          console.error("复制失败:", err);
          // 复制失败提示
          const originalBackground = cssContent.style.backgroundColor;

          cssContent.style.backgroundColor = "rgba(239, 68, 68, 0.1)";

          setTimeout(() => {
            cssContent.style.backgroundColor = originalBackground;
          }, 1000);
        }
      );
    };

    // 创建Tailwind内容区域
    const tailwindContent = document.createElement("pre");
    tailwindContent.className = "tailwind-content";
    tailwindContent.style.cssText = `
      margin: 0;
      margin-bottom: 10px;
      white-space: pre-wrap;
      word-break: break-all;
      font-family: 'SF Mono', Consolas, Monaco, 'Andale Mono', monospace;
      font-size: 14px;
      color: #2563eb;
      line-height: 1.8;
      display: block;
      padding: 16px;
      background-color: #f1f5f9;
      border-radius: 8px;
      animation: fadeIn 0.3s ease-in-out;
      box-shadow: 0 1px 3px rgba(0,0,0,0.05);
      border: 1px solid rgba(0,0,0,0.05);
      cursor: pointer;
    `;
    tailwindContent.textContent = tailwindCss;

    // 添加双击复制功能
    tailwindContent.ondblclick = (event) => {
      // 阻止默认行为,防止页面滚动
      event.preventDefault();

      // 获取内容并替换换行符为空格
      let contentToCopy = tailwindContent.textContent;
      contentToCopy = contentToCopy.replace(/\n/g, " ");

      // 复制到剪贴板
      navigator.clipboard.writeText(contentToCopy).then(
        () => {
          // 复制成功提示 - 添加临时样式变化
          const originalBackground = tailwindContent.style.backgroundColor;
          const originalColor = tailwindContent.style.color;

          tailwindContent.style.backgroundColor = "rgba(16, 185, 129, 0.1)";
          tailwindContent.style.color = "rgba(16, 185, 129, 1)";

          setTimeout(() => {
            tailwindContent.style.backgroundColor = originalBackground;
            tailwindContent.style.color = originalColor;
          }, 1000);
        },
        (err) => {
          console.error("复制失败:", err);
          // 复制失败提示
          const originalBackground = tailwindContent.style.backgroundColor;

          tailwindContent.style.backgroundColor = "rgba(239, 68, 68, 0.1)";

          setTimeout(() => {
            tailwindContent.style.backgroundColor = originalBackground;
          }, 1000);
        }
      );
    };

    // 添加双击复制提示
    const copyHintText = document.createElement("div");
    copyHintText.style.cssText = `
      font-size: 13px;
      color: #4a90e2;
      text-align: center;
      margin-bottom: 10px;
      font-style: italic;
      padding: 5px;
      border-radius: 4px;
      background-color: rgba(74, 144, 226, 0.08);
      transition: all 0.2s ease;
      cursor: help;
    `;
    copyHintText.innerHTML = "✨ 双击可复制内容 ✨";
    copyHintText.onmouseover = () => {
      copyHintText.style.backgroundColor = "rgba(74, 144, 226, 0.15)";
    };
    copyHintText.onmouseout = () => {
      copyHintText.style.backgroundColor = "rgba(74, 144, 226, 0.08)";
    };
    contentContainer.appendChild(copyHintText);

    // 添加标签切换功能
    cssTab.onclick = (event) => {
      // 阻止默认行为,防止页面滚动
      event.preventDefault();

      cssTab.style.borderBottom = "2px solid #4a90e2";
      cssTab.style.fontWeight = "600";
      cssTab.style.color = "#4a90e2";
      cssTab.style.backgroundColor = "rgba(74, 144, 226, 0.08)";
      tailwindTab.style.borderBottom = "2px solid transparent";
      tailwindTab.style.fontWeight = "500";
      tailwindTab.style.color = "#666";
      tailwindTab.style.backgroundColor = "transparent";
      cssContent.style.display = "block";
      tailwindContent.style.display = "none";

      // 添加动画效果
      cssContent.style.animation = "fadeIn 0.3s ease-in-out";
    };

    tailwindTab.onclick = (event) => {
      // 阻止默认行为,防止页面滚动
      event.preventDefault();

      tailwindTab.style.borderBottom = "2px solid #4a90e2";
      tailwindTab.style.fontWeight = "600";
      tailwindTab.style.color = "#4a90e2";
      tailwindTab.style.backgroundColor = "rgba(74, 144, 226, 0.08)";
      cssTab.style.borderBottom = "2px solid transparent";
      cssTab.style.fontWeight = "500";
      cssTab.style.color = "#666";
      cssTab.style.backgroundColor = "transparent";
      cssContent.style.display = "none";
      tailwindContent.style.display = "block";

      // 添加动画效果
      tailwindContent.style.animation = "fadeIn 0.3s ease-in-out";
    };

    // 组装弹窗
    contentContainer.appendChild(cssContent);
    contentContainer.appendChild(tailwindContent);

    popup.appendChild(titleBar);
    popup.appendChild(tabContainer);
    popup.appendChild(contentContainer);
    document.body.appendChild(popup);

    // 添加拖动功能 - 改进版本
    let isDragging = false;
    let offsetX, offsetY;

    titleBar.addEventListener("mousedown", (e) => {
      // 阻止默认行为,防止页面滚动
      e.preventDefault();

      isDragging = true;
      offsetX = e.clientX - popup.getBoundingClientRect().left;
      offsetY = e.clientY - popup.getBoundingClientRect().top;
      popup.style.transition = "none";
      popup.style.opacity = "0.92";
      popup.style.transform = "scale(1.01)";
      document.body.style.cursor = "grabbing";
      titleBar.style.cursor = "grabbing";
    });

    document.addEventListener(
      "mousemove",
      (e) => {
        if (isDragging) {
          // 阻止默认行为,防止页面滚动
          e.preventDefault();

          const x = e.clientX - offsetX;
          const y = e.clientY - offsetY;

          // 确保弹窗不会被拖出视口
          const maxX = window.innerWidth - popup.offsetWidth;
          const maxY = window.innerHeight - popup.offsetHeight;

          popup.style.left = `${Math.max(0, Math.min(x, maxX))}px`;
          popup.style.right = "auto";
          popup.style.top = `${Math.max(0, Math.min(y, maxY))}px`;
          popup.style.bottom = "auto";
        }
      },
      { passive: false }
    ); // 设置passive为false,允许阻止默认行为

    document.addEventListener(
      "mouseup",
      (e) => {
        if (isDragging) {
          // 阻止默认行为,防止页面滚动
          e.preventDefault();

          isDragging = false;
          popup.style.transition = "all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)";
          popup.style.opacity = "1";
          popup.style.transform = "scale(1)";
          document.body.style.cursor = "default";
          titleBar.style.cursor = "move";
        }
      },
      { passive: false }
    ); // 设置passive为false,允许阻止默认行为

    // 添加窗口大小调整时的位置修正
    window.addEventListener("resize", () => {
      const rect = popup.getBoundingClientRect();
      const maxX = window.innerWidth - popup.offsetWidth;
      const maxY = window.innerHeight - popup.offsetHeight;

      if (rect.right > window.innerWidth) {
        popup.style.left = `${Math.max(0, maxX)}px`;
      }

      if (rect.bottom > window.innerHeight) {
        popup.style.top = `${Math.max(0, maxY)}px`;
      }
    });
  }

  /**
   * 防抖函数
   * @param {Function} func - 要执行的函数
   * @param {number} wait - 等待时间
   * @param {Object} options - 配置选项
   * @returns {Function} - 防抖处理后的函数
   */
  function debounce(func, wait, options) {
    let lastArgs, lastThis, maxWait, result, timerId, lastCallTime;
    let lastInvokeTime = 0;
    let leading = false;
    let maxing = false;
    let trailing = true;

    if (typeof options === "object") {
      leading = !!options.leading;
      maxing = "maxWait" in options;
      maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
      trailing = "trailing" in options ? !!options.trailing : trailing;
    }

    function invokeFunc(time) {
      const args = lastArgs;
      const thisArg = lastThis;

      lastArgs = lastThis = undefined;
      lastInvokeTime = time;
      result = func.apply(thisArg, args);
      return result;
    }

    function leadingEdge(time) {
      lastInvokeTime = time;
      timerId = setTimeout(timerExpired, wait);
      return leading ? invokeFunc(time) : result;
    }

    function remainingWait(time) {
      const timeSinceLastCall = time - lastCallTime;
      const timeSinceLastInvoke = time - lastInvokeTime;
      const timeWaiting = wait - timeSinceLastCall;

      return maxing
        ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
        : timeWaiting;
    }

    function shouldInvoke(time) {
      const timeSinceLastCall = time - lastCallTime;
      const timeSinceLastInvoke = time - lastInvokeTime;

      return (
        lastCallTime === undefined ||
        timeSinceLastCall >= wait ||
        timeSinceLastCall < 0 ||
        (maxing && timeSinceLastInvoke >= maxWait)
      );
    }

    function timerExpired() {
      const time = Date.now();
      if (shouldInvoke(time)) {
        return trailingEdge(time);
      }
      timerId = setTimeout(timerExpired, remainingWait(time));
    }

    function trailingEdge(time) {
      timerId = undefined;

      if (trailing && lastArgs) {
        return invokeFunc(time);
      }
      lastArgs = lastThis = undefined;
      return result;
    }

    function cancel() {
      if (timerId !== undefined) {
        clearTimeout(timerId);
      }
      lastInvokeTime = 0;
      lastArgs = lastCallTime = lastThis = timerId = undefined;
    }

    function flush() {
      return timerId === undefined ? result : trailingEdge(Date.now());
    }

    function debounced() {
      const time = Date.now();
      const isInvoking = shouldInvoke(time);

      lastArgs = arguments;
      lastThis = this;
      lastCallTime = time;

      if (isInvoking) {
        if (timerId === undefined) {
          return leadingEdge(lastCallTime);
        }
        if (maxing) {
          timerId = setTimeout(timerExpired, wait);
          return invokeFunc(lastCallTime);
        }
      }
      if (timerId === undefined) {
        timerId = setTimeout(timerExpired, wait);
      }
      return result;
    }
    debounced.cancel = cancel;
    debounced.flush = flush;
    return debounced;
  }

  /**
   * 获取数组的最后一个元素
   * @param {Array} array - 输入数组
   * @returns {*} - 最后一个元素
   */
  function last(array) {
    const length = array == null ? 0 : array.length;
    return length ? array[length - 1] : undefined;
  }

  /**
   * 去除字符串两端的空白
   * @param {string} str - 输入字符串
   * @returns {string} - 处理后的字符串
   */
  function trim(str) {
    return str ? str.trim() : "";
  }

  // 立即执行的函数,用于监视抽屉的打开状态
  (async () => {
    let obs = new MutationObserver(() => {
      // 获取所有抽屉元素
      const drawerList = document.querySelectorAll(
        "#detail_container .mu-drawer"
      );

      // 查找打开的抽屉
      let openDrawer = Array.from(drawerList).find((d) =>
        d.classList.contains("open")
      );
      // 如果找到新打开的抽屉,开始观察它
      if (openDrawer && ref.current !== openDrawer) {
        observeDrawer(openDrawer);
      }
    });

    // 观察整个文档body的变化
    obs.observe(document.body, {
      subtree: true,
      attributes: true,
      childList: true,
    });

    // 添加初始化提示
    console.log(
      "%c[CSS提取器]",
      "color:#3799a8; font-weight:bold;",
      "已初始化,等待蓝湖设计稿打开..."
    );
  })();
})();