Forráskód Böngészése

release: v0.0.6
- 优化页面信息卡片样式和动画
- 改进输入框焦点管理
- 提升整体用户体验

alibct 7 hónapja
szülő
commit
9eda48c563
7 módosított fájl, 309 hozzáadás és 4 törlés
  1. 13 0
      CHANGELOG.md
  2. 160 0
      css/chat.css
  3. 88 3
      js/chat-ui.js
  4. 37 0
      js/content.js
  5. 1 0
      js/page-analyzer.js
  6. 2 1
      manifest.json
  7. 8 0
      sidebar.html

+ 13 - 0
CHANGELOG.md

@@ -1,5 +1,18 @@
 # 更新日志
 
+## [0.0.6] - 2024-03-xx
+
+### 优化
+
+- 改进页面信息卡片
+  - 添加标题滚动效果
+  - 优化渐变遮罩样式
+  - 添加星星动画效果
+- 优化用户体验
+  - 改进输入框焦点管理
+  - AI 回复完成后自动聚焦
+  - 优化视觉反馈效果
+
 ## [0.0.5] - 2024-03-xx
 
 ### 优化

+ 160 - 0
css/chat.css

@@ -595,3 +595,163 @@
   opacity: 1; /* 保持完全不透明 */
   cursor: pointer;
 }
+
+/* 页面信息卡片 */
+.page-info-card {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  padding: 12px 16px;
+  margin: 0 16px 8px; /* 保持底部间距为8px */
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+/* 网站图标 */
+.page-favicon {
+  width: 16px;
+  height: 16px;
+  flex-shrink: 0;
+}
+
+/* 页面标题容器 */
+.page-title-container {
+  flex: 1;
+  position: relative;
+  overflow: hidden;
+  white-space: nowrap;
+  scrollbar-width: none;
+  -ms-overflow-style: none;
+}
+
+/* 隐藏滚动条但保持可滚动 */
+.page-title-container::-webkit-scrollbar {
+  display: none;
+}
+
+/* 页面标题 */
+.page-title {
+  font-size: 14px;
+  color: #333;
+  margin: 0;
+  display: inline-block;
+  position: relative; /* 添加相对定位 */
+  padding-right: 20px;
+  /* 移除这些可能导致标题消失的样式 */
+  /* padding-left: 100%; */
+  /* transform: translateX(-100%); */
+}
+
+/* 当容器被hover时启动滚动动画 */
+.page-title-container:hover .page-title {
+  animation: scrollText 20s linear infinite; /* 增加动画时间到20秒 */
+}
+
+/* 修改滚动动画逻辑 */
+@keyframes scrollText {
+  from {
+    transform: translateX(0);
+  }
+  to {
+    transform: translateX(-100%);
+  }
+}
+
+/* 优化渐变遮罩 */
+.page-title-container::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 30px; /* 减小遮罩宽度 */
+  height: 100%;
+  background: linear-gradient(
+    to right,
+    rgba(255, 255, 255, 0),
+    rgba(255, 255, 255, 0.8)
+  ); /* 降低不透明度 */
+  pointer-events: none;
+}
+
+/* 添加左侧渐变遮罩 */
+.page-title-container::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 30px; /* 减小遮罩宽度 */
+  height: 100%;
+  background: linear-gradient(
+    to left,
+    rgba(255, 255, 255, 0),
+    rgba(255, 255, 255, 0.8)
+  ); /* 降低不透明度 */
+  pointer-events: none;
+  z-index: 1;
+}
+
+/* 滚动时显示左侧遮罩 */
+.page-title-container:hover::before {
+  opacity: 1;
+}
+
+/* 总结按钮 */
+.summarize-button {
+  position: relative; /* 添加相对定位 */
+  padding: 6px 12px;
+  color: #1a73e8;
+  background: #e8f0fe;
+  border: none;
+  border-radius: 4px;
+  font-size: 13px;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  flex-shrink: 0;
+  overflow: hidden; /* 确保星星不会溢出按钮区域 */
+}
+
+/* 星星元素 */
+.summarize-button::after {
+  content: "✦";
+  position: absolute;
+  top: 0;
+  right: 2px;
+  font-size: 10px;
+  opacity: 0;
+  transform: translateY(10px);
+  transition: all 0.3s ease;
+}
+
+/* 鼠标悬停时的动画效果 */
+.summarize-button:hover {
+  background: #d2e3fc;
+  transform: translateY(-1px);
+}
+
+.summarize-button:hover::after {
+  opacity: 1;
+  transform: translateY(0);
+  animation: twinkle 1s infinite;
+}
+
+/* 点击效果 */
+.summarize-button:active {
+  transform: translateY(0);
+}
+
+/* 星星闪烁动画 */
+@keyframes twinkle {
+  0% {
+    opacity: 1;
+    transform: scale(1) rotate(0deg);
+  }
+  50% {
+    opacity: 0.5;
+    transform: scale(1.2) rotate(180deg);
+  }
+  100% {
+    opacity: 1;
+    transform: scale(1) rotate(360deg);
+  }
+}

+ 88 - 3
js/chat-ui.js

@@ -46,6 +46,9 @@ class ChatUI {
     this.isTyping = false; // 添加打字状态标记
     this.loadingDiv = null; // 添加加载动画的引用
     this.inputWrapper = document.querySelector(".input-wrapper");
+
+    // 初始化页面信息卡片
+    this.initPageInfoCard();
   }
 
   async init() {
@@ -146,7 +149,7 @@ class ChatUI {
       await this.addMessage(response, "assistant", true);
 
       this.stopButton.classList.remove("show");
-      this.setInputState(false); // 恢复输入框
+      this.setInputState(false); // 这里会自动聚焦输入框
 
       this.aiService.updateContext(response, "assistant");
     } catch (error) {
@@ -156,7 +159,7 @@ class ChatUI {
       }
 
       this.stopButton.classList.remove("show");
-      this.setInputState(false); // 恢复输入框
+      this.setInputState(false); // 这里也会自动聚焦输入框
       this.isTyping = false;
 
       if (error.message === "REQUEST_ABORTED") {
@@ -481,7 +484,7 @@ class ChatUI {
       }
 
       this.stopButton.classList.remove("show");
-      this.setInputState(false); // 恢复输入框状态
+      this.setInputState(false); // 中断后也自动聚焦输入框
 
       this.addMessage("用户手动停止生成", "assistant", false, true);
     } catch (error) {
@@ -497,6 +500,88 @@ class ChatUI {
       this.inputWrapper.classList.add("generating");
     } else {
       this.inputWrapper.classList.remove("generating");
+      // AI回复完成后,自动聚焦到输入框
+      this.input.focus();
+    }
+  }
+
+  /**
+   * 初始化页面信息卡片
+   */
+  initPageInfoCard() {
+    // 从父窗口获取页面信息
+    window.addEventListener("message", (event) => {
+      if (event.data.type === "PAGE_INFO") {
+        const pageInfo = event.data.pageInfo;
+
+        // 更新卡片内容
+        const favicon = document.querySelector(".page-favicon");
+        const title = document.querySelector(".page-title");
+
+        // 设置网站图标
+        favicon.src = pageInfo.favicon;
+        favicon.onerror = () => {
+          // 如果图标加载失败,使用默认图标
+          favicon.src = chrome.runtime.getURL("images/icon16.png");
+        };
+
+        // 设置页面标题
+        title.textContent = pageInfo.title;
+      }
+    });
+  }
+
+  /**
+   * 获取页面favicon
+   * @returns {string} favicon URL
+   */
+  getPageFavicon() {
+    // 尝试获取页面favicon
+    const iconLink = document.querySelector('link[rel*="icon"]');
+    if (iconLink) return iconLink.href;
+
+    // 如果没有找到,返回网站根目录的favicon.ico
+    const url = new URL(window.location.href);
+    return `${url.protocol}//${url.hostname}/favicon.ico`;
+  }
+
+  /**
+   * 处理总结请求
+   */
+  async handleSummarize() {
+    try {
+      // 显示加载状态
+      this.setInputState(true);
+      this.loadingDiv = this.createLoadingMessage();
+
+      // 获取页面分析结果
+      const pageContext = window.pageAnalyzer.analyzePage();
+
+      // 构建提示词
+      const prompt = `请总结当前页面的主要内容:
+标题:${pageContext.title}
+URL:${pageContext.url}
+主要内容:${pageContext.mainContent}`;
+
+      // 发送分析请求
+      const response = await this.aiService.sendMessage(prompt);
+
+      // 显示分析结果
+      if (this.loadingDiv) {
+        this.loadingDiv.remove();
+        this.loadingDiv = null;
+      }
+
+      await this.addMessage(response, "assistant", true);
+      this.setInputState(false); // 总结完成后自动聚焦输入框
+    } catch (error) {
+      console.error("Failed to summarize page:", error);
+      this.addMessage(
+        "抱歉,页面总结过程中出现错误,请稍后重试。",
+        "assistant",
+        false
+      );
+      this.setInputState(false); // 错误后也自动聚焦输入框
     }
   }
 }

+ 37 - 0
js/content.js

@@ -183,6 +183,38 @@ class SidebarManager {
     wrapper.remove();
   }
 
+  /**
+   * 发送页面信息到iframe
+   */
+  sendPageInfo() {
+    const iframe = document.getElementById(this.sidebarId);
+    if (!iframe) return;
+
+    // 获取页面favicon
+    let favicon = "";
+    const iconLink = document.querySelector('link[rel*="icon"]');
+    if (iconLink) {
+      favicon = iconLink.href;
+    } else {
+      // 如果没有找到,使用网站根目录的favicon.ico
+      const url = new URL(window.location.href);
+      favicon = `${url.protocol}//${url.hostname}/favicon.ico`;
+    }
+
+    // 发送页面信息到iframe
+    iframe.contentWindow.postMessage(
+      {
+        type: "PAGE_INFO",
+        pageInfo: {
+          favicon: favicon,
+          title: document.title,
+          url: window.location.href,
+        },
+      },
+      "*"
+    );
+  }
+
   /**
    * 创建侧边栏
    */
@@ -205,6 +237,11 @@ class SidebarManager {
 
       this.isOpen = true;
       await Utils.setStorageData(SidebarManager.CONFIG.STORAGE_KEY, true);
+
+      // 在iframe加载完成后发送页面信息
+      iframe.onload = () => {
+        this.sendPageInfo();
+      };
     } catch (error) {
       console.error("Failed to create sidebar:", error);
       this.unwrapPageContent();

+ 1 - 0
js/page-analyzer.js

@@ -0,0 +1 @@
+ 

+ 2 - 1
manifest.json

@@ -1,7 +1,7 @@
 {
   "manifest_version": 3,
   "name": "派维斯智能体助手",
-  "version": "0.0.5",
+  "version": "0.0.6",
   "description": "一个辅助用户处理业务流程的智能体助手",
   "author": "Paiwise Team",
   "permissions": [
@@ -37,6 +37,7 @@
       "js": [
         "js/config.js",
         "js/utils.js",
+        "js/page-analyzer.js",
         "js/ai-service.js",
         "js/chat-ui.js",
         "js/content.js"

+ 8 - 0
sidebar.html

@@ -30,6 +30,14 @@
       </div>
 
       <!-- 输入区域 -->
+      <div class="page-info-card">
+        <img class="page-favicon" src="" alt="网站图标" />
+        <div class="page-title-container">
+          <p class="page-title"></p>
+        </div>
+        <button class="summarize-button">总结</button>
+      </div>
+
       <div class="chat-input-container">
         <div class="input-wrapper">
           <textarea