Jelajahi Sumber

修复jsonformat的样式bug,以及option页面的样式bug

zxlie 4 bulan lalu
induk
melakukan
5bfd0aa366

+ 107 - 35
apps/json-format/content-script.css

@@ -87,6 +87,32 @@ html.fh-jf .item {
     padding-bottom: 1px;
 }
 
+/* 行悬停效果 - 使用JavaScript控制的类 */
+html.fh-jf .item.fh-hover {
+    background-color: rgba(0, 0, 0, 0.02);
+    border-radius: 2px;
+}
+
+/* 深色主题悬停效果 */
+html.fh-jf .theme-dark .item.fh-hover {
+    background-color: rgba(255, 255, 255, 0.02);
+}
+
+/* VS Code主题悬停效果 */
+html.fh-jf .theme-vscode .item.fh-hover {
+    background-color: rgba(255, 255, 255, 0.02);
+}
+
+/* GitHub主题悬停效果 */
+html.fh-jf .theme-github .item.fh-hover {
+    background-color: rgba(0, 0, 0, 0.02);
+}
+
+/* Light主题悬停效果 */
+html.fh-jf .theme-light .item.fh-hover {
+    background-color: rgba(0, 0, 0, 0.02);
+}
+
 html.fh-jf .item .kv-list {
     display: block;
     padding-left: 24px;
@@ -113,16 +139,39 @@ html.fh-jf .item .brace {
 html.fh-jf .item .expand {
     width: 20px;
     height: 18px;
-    display: block;
+    display: inline-block;
     position: absolute;
-    left: -2px;
-    top: 4px;
+    left: -20px;
+    top: 2px;
     z-index: 5;
     opacity: 0.35;
     -webkit-user-select: none;
     cursor: pointer;
 }
 
+/* 当展开按钮在key前面时 */
+html.fh-jf .item > .expand:first-child {
+    position: absolute;
+    left: 4px;
+    top: 2px;
+}
+
+/* 根级对象和数组的展开按钮 */
+html.fh-jf .item-object > .expand:first-child,
+html.fh-jf .item-array > .expand:first-child {
+    position: absolute;
+    left: 4px;
+    top: 2px;
+}
+
+/* 数组块元素的展开按钮 */
+html.fh-jf .item-block > .expand:first-child {
+    position: absolute;
+    left: 4px;
+    top: 2px;
+}
+
+
 html.fh-jf .item .expand:after {
     content: "\25bc";
 }
@@ -163,11 +212,17 @@ html.fh-jf .item.collapsed .item {
 
 html.fh-jf .item.collapsed > .expand {
     -webkit-transform: rotate(-90deg);
-    top: -1px
+    top: -4px;
+    left: -2px;
 }
 html.fh-jf .remove-quote .quote {
     display: none;
 }
+
+/* 展开按钮在key前面时不影响后续元素 */
+html.fh-jf .item > .expand:first-child + .quote {
+    margin-left: 0;
+}
 /*================json format style end===================*/
 
 
@@ -277,7 +332,7 @@ html.fh-jf  body {
     margin: 0;
 }
 
-html..fh-jf body {
+html.fh-jf body {
     padding: 0 8px;
 }
 
@@ -774,105 +829,121 @@ html.fh-jf body.theme-default {
 .theme-dark {
     background:#000;
 }
-.theme-dark .x-toolbar {
+html.fh-jf .theme-dark .x-toolbar {
     background: -webkit-linear-gradient(#222,#222,#111);
     border: 1px solid #333;
     border-bottom-color: #363636;
     color:#ddd;
 }
-.theme-dark .x-toolbar .x-a-title {
+html.fh-jf .theme-dark .x-toolbar .x-a-title {
     color:#48b;
 }
-.theme-dark .xjf-btn {
+html.fh-jf .theme-dark .xjf-btn {
     background:-webkit-linear-gradient(#222,#222,#111);
     border:1px solid #444;
     color:#ddd;
 }
-.theme-dark .xjf-btn:hover {
+html.fh-jf .theme-dark .xjf-btn:hover {
     background:-webkit-linear-gradient(#333,#333,#222);
 }
-.theme-dark #statusBar {
+html.fh-jf .theme-dark #statusBar {
     background: #333;
     color: #ddd;
     border-top: 1px solid #555;
 }
-.theme-dark .boxOpt {
+html.fh-jf .theme-dark .boxOpt {
     background: -webkit-linear-gradient(#222,#222,#111);
     border: 1px solid #333;
 }
-.theme-dark .boxOpt a:hover {
+html.fh-jf .theme-dark .boxOpt a:hover {
     color:#eee;
 }
-.theme-dark .mod-setting-panel {
+html.fh-jf .theme-dark .mod-setting-panel {
     background: #222;
     color: #fff;
     border-color: #444;
     box-shadow: 1px 1px #111;
 }
-.theme-dark .mod-setting-panel li:hover {
+html.fh-jf .theme-dark .mod-setting-panel li:hover {
     color:#ff0;
 }
-.theme-dark .mod-setting-panel input[name="maxlength"] {
+html.fh-jf .theme-dark .mod-setting-panel input[name="maxlength"] {
     background: #000;
     border: 1px solid #555;
     color: #fff;
 }
 
-.theme-dark .item .key {
+html.fh-jf .theme-dark .item .key {
     color: #fff;
 }
 
-.theme-dark .item .kv-list {
+html.fh-jf .theme-dark .item .kv-list {
     border-left: 1px dashed #222;
 }
-.theme-dark .item .string {
+html.fh-jf .theme-dark .item .string {
     color: #0f0;
 }
 
-.theme-dark .item .string a {
+html.fh-jf .theme-dark .item .string a {
     color: #369ad6;
     text-decoration: underline;
 }
 
-.theme-dark .item .string a:hover {
+html.fh-jf .theme-dark .item .string a:hover {
     color: #b00;
 }
-.theme-dark .item .brace,
-.theme-dark .item .colon,
-.theme-dark .item .comma{
+html.fh-jf .theme-dark .item .brace,
+html.fh-jf .theme-dark .item .colon,
+html.fh-jf .theme-dark .item .comma{
     color:#eaeaea;
 }
 
-.theme-dark .item .bool,
-.theme-dark .item .null,
-.theme-dark .item .number {
+html.fh-jf .theme-dark .item .bool,
+html.fh-jf .theme-dark .item .null,
+html.fh-jf .theme-dark .item .number {
     font-weight: bold;
     color: #f00
 }
-.theme-dark .item .item-object:hover > span,
-.theme-dark .item .item-array:hover > span,
-.theme-dark .item .item-block:hover > span{
+html.fh-jf .theme-dark .item .item-object:hover > span,
+html.fh-jf .theme-dark .item .item-array:hover > span,
+html.fh-jf .theme-dark .item .item-block:hover > span{
     font-weight: bold;
     color: orange;
 }
 
-.theme-dark .item .item-line:hover,
-.theme-dark .item-line.x-selected {
+html.fh-jf .theme-dark .item .item-line:hover,
+html.fh-jf .theme-dark .item-line.x-selected {
     background: #111;
 }
 
-.theme-dark .item .item-line:hover span ,
-.theme-dark .item.x-selected>span {
+html.fh-jf .theme-dark .item .item-line:hover span ,
+html.fh-jf .theme-dark .item.x-selected>span {
     font-weight: bolder;
     background: #444;
 }
-.theme-dark .item .quote {
+html.fh-jf .theme-dark .item .quote {
     color:#eaeaea;
 }
-.theme-dark .item .expand {
+html.fh-jf .theme-dark .item .expand {
     color:#fff;
 }
+html.fh-jf .theme-dark .x-donate-link {
+    background-color: #222;
+    border: 1px solid #444;
+    color: #ddd;
+}
+html.fh-jf .theme-dark .x-donate-link:hover {
+    background-color: #333;
+}
 
+html.fh-jf .theme-dark .x-donate-link a {
+    color: #ddd;
+}
+html.fh-jf .theme-dark .x-other-tools {
+    background-color: #222;
+    border: 1px solid #444;
+    color: #ddd;
+}
 
 /*================ 皮肤:theme-vscode ===================*/
 .theme-vscode .item .key {
@@ -974,3 +1045,4 @@ html.fh-jf body.theme-default {
 .t-collapse .fe-feedback #toggleBtn{
     padding-bottom: 20px;
 }
+

+ 66 - 2
apps/json-format/format-lib.js

@@ -248,13 +248,31 @@ window.Formatter = (function () {
 
         } while (curEl.length && !curEl.hasClass('rootItem'));
 
-        let path = keys.join('#@#').replace(/#@#\[/g, '[').replace(/#@#/g, '.');
+        // 过滤掉空值和无效的key,避免产生多余的点号
+        let validKeys = keys.filter(key => key && key.trim() !== '');
+        
+        // 构建路径:正确处理对象属性和数组索引的连接
+        let path = '';
+        for (let i = 0; i < validKeys.length; i++) {
+            let key = validKeys[i];
+            if (key.startsWith('[') && key.endsWith(']')) {
+                // 数组索引,直接拼接(前面永远不需要点号)
+                path += key;
+            } else {
+                // 对象属性
+                if (i > 0) {
+                    // 对象属性前面需要点号(数组索引后面的属性也需要点号)
+                    path += '.';
+                }
+                path += key;
+            }
+        }
 
         let jfPath = $('#jsonPath');
         if (!jfPath.length) {
             jfPath = $('<span id="jsonPath"/>').prependTo(jfStatusBar);
         }
-        jfPath.html('当前节点:JSON.' + path);
+        jfPath.html('当前节点:$.' + path);
     };
 
     // 给某个节点增加操作项
@@ -475,6 +493,51 @@ window.Formatter = (function () {
             }
         });
 
+        // 行悬停效果:只高亮当前直接悬停的item,避免嵌套冒泡
+        let currentHoverElement = null;
+        
+        $('#jfContent .item').bind('mouseenter', function (e) {
+            // 只处理视觉效果,不触发任何其他逻辑
+            
+            // 清除之前的悬停样式
+            if (currentHoverElement) {
+                currentHoverElement.removeClass('fh-hover');
+            }
+            
+            // 添加当前悬停样式
+            let el = $(this);
+            el.addClass('fh-hover');
+            currentHoverElement = el;
+            
+            // 严格阻止事件冒泡和默认行为
+            e.stopPropagation();
+            e.stopImmediatePropagation();
+            e.preventDefault();
+        });
+        
+        $('#jfContent .item').bind('mouseleave', function (e) {
+            // 只处理视觉效果,不触发任何其他逻辑
+            let el = $(this);
+            el.removeClass('fh-hover');
+            
+            // 如果当前移除的元素是记录的悬停元素,清空记录
+            if (currentHoverElement && currentHoverElement[0] === el[0]) {
+                currentHoverElement = null;
+            }
+            
+            // 严格阻止事件冒泡和默认行为
+            e.stopPropagation();
+            e.stopImmediatePropagation();
+        });
+        
+        // 为整个jfContent区域添加鼠标离开事件,确保彻底清除悬停样式
+        $('#jfContent').bind('mouseleave', function (e) {
+            if (currentHoverElement) {
+                currentHoverElement.removeClass('fh-hover');
+                currentHoverElement = null;
+            }
+        });
+
     };
     
     /**
@@ -599,3 +662,4 @@ window.Formatter = (function () {
 
 
 
+

+ 2 - 1
apps/json-format/index.js

@@ -317,7 +317,7 @@ new Vue({
         },
 
         setDemo: function () {
-            let demo = '{"BigIntSupported":995815895020119788889,"date":"20180322","message":"Success !","status":200,"city":"北京","count":632,"data":{"shidu":"34%","pm25":73,"pm10":91,"quality":"良","wendu":"5","ganmao":"极少数敏感人群应减少户外活动","yesterday":{"date":"21日星期三","sunrise":"06:19","high":"高温 11.0℃","low":"低温 1.0℃","sunset":"18:26","aqi":85,"fx":"南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},"forecast":[{"date":"22日星期四","sunrise":"06:17","high":"高温 17.0℃","low":"低温 1.0℃","sunset":"18:27","aqi":98,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"23日星期五","sunrise":"06:16","high":"高温 18.0℃","low":"低温 5.0℃","sunset":"18:28","aqi":118,"fx":"无持续风向","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},{"date":"24日星期六","sunrise":"06:14","high":"高温 21.0℃","low":"低温 7.0℃","sunset":"18:29","aqi":52,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"25日星期日","sunrise":"06:13","high":"高温 22.0℃","low":"低温 7.0℃","sunset":"18:30","aqi":71,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"26日星期一","sunrise":"06:11","high":"高温 21.0℃","low":"低温 8.0℃","sunset":"18:31","aqi":97,"fx":"西南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"}]}}';
+            let demo = '{"BigIntSupported":995815895020119788889,"date":"20180322","url":"https://www.baidu.com?wd=fehelper","message":"Success !","status":200,"city":"北京","count":632,"data":{"shidu":"34%","pm25":73,"pm10":91,"quality":"良","wendu":"5","ganmao":"极少数敏感人群应减少户外活动","yesterday":{"date":"21日星期三","sunrise":"06:19","high":"高温 11.0℃","low":"低温 1.0℃","sunset":"18:26","aqi":85,"fx":"南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},"forecast":[{"date":"22日星期四","sunrise":"06:17","high":"高温 17.0℃","low":"低温 1.0℃","sunset":"18:27","aqi":98,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"23日星期五","sunrise":"06:16","high":"高温 18.0℃","low":"低温 5.0℃","sunset":"18:28","aqi":118,"fx":"无持续风向","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"},{"date":"24日星期六","sunrise":"06:14","high":"高温 21.0℃","low":"低温 7.0℃","sunset":"18:29","aqi":52,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"25日星期日","sunrise":"06:13","high":"高温 22.0℃","low":"低温 7.0℃","sunset":"18:30","aqi":71,"fx":"西南风","fl":"<3级","type":"晴","notice":"愿你拥有比阳光明媚的心情"},{"date":"26日星期一","sunrise":"06:11","high":"高温 21.0℃","low":"低温 8.0℃","sunset":"18:31","aqi":97,"fx":"西南风","fl":"<3级","type":"多云","notice":"阴晴之间,谨防紫外线侵扰"}]}}';
             editor.setValue(demo);
             this.$nextTick(() => {
                 this.format();
@@ -325,3 +325,4 @@ new Vue({
         }
     }
 });
+

+ 215 - 6
apps/json-format/json-worker.js

@@ -120,6 +120,22 @@ function htmlspecialchars(str) {
     return str;
 }
 
+// 格式化字符串值,如果是URL则转换为链接
+function formatStringValue(str) {
+    // URL正则表达式,匹配 http/https/ftp 协议的URL
+    const urlRegex = /^(https?:\/\/|ftp:\/\/)[^\s<>"'\\]+$/i;
+    
+    if (urlRegex.test(str)) {
+        // 如果是URL,转换为链接
+        const escapedUrl = htmlspecialchars(str);
+        return '<a href="' + escapedUrl + '" target="_blank" rel="noopener noreferrer">' + htmlspecialchars(str) + '</a>';
+    } else {
+        // 直接显示解析后的字符串内容,不需要重新转义
+        // 这样可以保持用户原始输入的意图
+        return htmlspecialchars(str);
+    }
+}
+
 // 格式化JSON为HTML
 function formatJsonToHtml(json) {
     return createNode(json).getHTML();
@@ -136,7 +152,7 @@ function createNode(value) {
             switch(this.type) {
                 case 'string':
                     return '<div class="item item-line"><span class="string">"' + 
-                        htmlspecialchars(this.value) + 
+                        formatStringValue(this.value) + 
                         '"</span></div>';
                 case 'number':
                     // 确保大数字不使用科学计数法
@@ -182,15 +198,22 @@ function createNode(value) {
                 let prop = this.value[key];
                 let childNode = createNode(prop);
                 
-                html += '<div class="item">' + 
-                    '<span class="quote">"</span>' +
+                html += '<div class="item">';
+                
+                // 如果值是对象或数组,在key前面添加展开按钮
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += '<span class="expand"></span>';
+                }
+                
+                html += '<span class="quote">"</span>' +
                     '<span class="key">' + htmlspecialchars(key) + '</span>' +
                     '<span class="quote">"</span>' +
                     '<span class="colon">: </span>';
                 
                 // 添加值
                 if (childNode.type === 'object' || childNode.type === 'array') {
-                    html += childNode.getHTML();
+                    // 对于对象和数组,将开始大括号/方括号放在同一行,但不包含展开按钮
+                    html += childNode.getInlineHTMLWithoutExpand();
                 } else {
                     html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
                 }
@@ -223,9 +246,10 @@ function createNode(value) {
                 
                 html += '<div class="item item-block">';
                 
-                // 添加值
+                // 如果数组元素是对象或数组,在前面添加展开按钮
                 if (childNode.type === 'object' || childNode.type === 'array') {
-                    html += childNode.getHTML();
+                    html += '<span class="expand"></span>';
+                    html += childNode.getInlineHTMLWithoutExpand();
                 } else {
                     html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
                 }
@@ -240,6 +264,190 @@ function createNode(value) {
             
             html += '</div><span class="brace">]</span></div>';
             return html;
+        },
+        
+        // 新增内联HTML方法,用于在同一行显示开始大括号/方括号
+        getInlineHTML: function() {
+            switch(this.type) {
+                case 'object':
+                    return this.getInlineObjectHTML();
+                case 'array':
+                    return this.getInlineArrayHTML();
+                default:
+                    return this.getHTML();
+            }
+        },
+        
+        // 新增不包含展开按钮的内联HTML方法
+        getInlineHTMLWithoutExpand: function() {
+            switch(this.type) {
+                case 'object':
+                    return this.getInlineObjectHTMLWithoutExpand();
+                case 'array':
+                    return this.getInlineArrayHTMLWithoutExpand();
+                default:
+                    return this.getHTML();
+            }
+        },
+        
+        getInlineObjectHTML: function() {
+            if (!this.value || Object.keys(this.value).length === 0) {
+                return '<span class="brace">{</span><span class="brace">}</span>';
+            }
+            
+            let html = '<span class="brace">{</span>' +
+                '<span class="expand"></span>' +
+                '<span class="ellipsis"></span>' +
+                '<div class="kv-list">';
+                
+            let keys = Object.keys(this.value);
+            keys.forEach((key, index) => {
+                let prop = this.value[key];
+                let childNode = createNode(prop);
+                
+                html += '<div class="item">';
+                
+                // 如果值是对象或数组,在key前面添加展开按钮
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += '<span class="expand"></span>';
+                }
+                
+                html += '<span class="quote">"</span>' +
+                    '<span class="key">' + htmlspecialchars(key) + '</span>' +
+                    '<span class="quote">"</span>' +
+                    '<span class="colon">: </span>';
+                
+                // 添加值
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += childNode.getInlineHTMLWithoutExpand();
+                } else {
+                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
+                }
+                
+                // 如果不是最后一个属性,添加逗号
+                if (index < keys.length - 1) {
+                    html += '<span class="comma">,</span>';
+                }
+                
+                html += '</div>';
+            });
+            
+            html += '</div><span class="brace">}</span>';
+            return html;
+        },
+        
+        getInlineArrayHTML: function() {
+            if (!this.value || this.value.length === 0) {
+                return '<span class="brace">[</span><span class="brace">]</span>';
+            }
+            
+            let html = '<span class="brace">[</span>' +
+                '<span class="expand"></span>' +
+                '<span class="ellipsis"></span>' +
+                '<div class="kv-list">';
+                
+            this.value.forEach((item, index) => {
+                let childNode = createNode(item);
+                
+                html += '<div class="item item-block">';
+                
+                // 如果数组元素是对象或数组,在前面添加展开按钮
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += '<span class="expand"></span>';
+                    html += childNode.getInlineHTMLWithoutExpand();
+                } else {
+                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
+                }
+                
+                // 如果不是最后一个元素,添加逗号
+                if (index < this.value.length - 1) {
+                    html += '<span class="comma">,</span>';
+                }
+                
+                html += '</div>';
+            });
+            
+            html += '</div><span class="brace">]</span>';
+            return html;
+        },
+        
+        getInlineObjectHTMLWithoutExpand: function() {
+            if (!this.value || Object.keys(this.value).length === 0) {
+                return '<span class="brace">{</span><span class="brace">}</span>';
+            }
+            
+            let html = '<span class="brace">{</span>' +
+                '<span class="ellipsis"></span>' +
+                '<div class="kv-list">';
+                
+            let keys = Object.keys(this.value);
+            keys.forEach((key, index) => {
+                let prop = this.value[key];
+                let childNode = createNode(prop);
+                
+                html += '<div class="item">';
+                
+                // 如果值是对象或数组,在key前面添加展开按钮
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += '<span class="expand"></span>';
+                }
+                
+                html += '<span class="quote">"</span>' +
+                    '<span class="key">' + htmlspecialchars(key) + '</span>' +
+                    '<span class="quote">"</span>' +
+                    '<span class="colon">: </span>';
+                
+                // 添加值
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += childNode.getInlineHTMLWithoutExpand();
+                } else {
+                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
+                }
+                
+                // 如果不是最后一个属性,添加逗号
+                if (index < keys.length - 1) {
+                    html += '<span class="comma">,</span>';
+                }
+                
+                html += '</div>';
+            });
+            
+            html += '</div><span class="brace">}</span>';
+            return html;
+        },
+        
+        getInlineArrayHTMLWithoutExpand: function() {
+            if (!this.value || this.value.length === 0) {
+                return '<span class="brace">[</span><span class="brace">]</span>';
+            }
+            
+            let html = '<span class="brace">[</span>' +
+                '<span class="ellipsis"></span>' +
+                '<div class="kv-list">';
+                
+            this.value.forEach((item, index) => {
+                let childNode = createNode(item);
+                
+                html += '<div class="item item-block">';
+                
+                // 如果数组元素是对象或数组,在前面添加展开按钮
+                if (childNode.type === 'object' || childNode.type === 'array') {
+                    html += '<span class="expand"></span>';
+                    html += childNode.getInlineHTMLWithoutExpand();
+                } else {
+                    html += childNode.getHTML().replace(/^<div class="item item-line">/, '').replace(/<\/div>$/, '');
+                }
+                
+                // 如果不是最后一个元素,添加逗号
+                if (index < this.value.length - 1) {
+                    html += '<span class="comma">,</span>';
+                }
+                
+                html += '</div>';
+            });
+            
+            html += '</div><span class="brace">]</span>';
+            return html;
         }
     };
     
@@ -259,3 +467,4 @@ function getType(value) {
     }
     return type;
 } 
+

+ 8 - 1
apps/options/index.css

@@ -220,7 +220,8 @@ body{
     background: #f0f0f0;
 }
 
-.category-list li.active {
+.category-list li.active,
+.my-tools li.active {
     background: #e6f7ff;
     color: #1890ff;
 }
@@ -480,6 +481,11 @@ body{
     color: #fff;
 }
 
+[data-theme='dark'] .my-tools li.active {
+    background: #177ddc;
+    color: #fff;
+}
+
 [data-theme='dark'] .view-toggle span {
     background: #3d3d3d;
     color: #bbb;
@@ -1669,3 +1675,4 @@ body{
 .dark-mode .navbar-actions .settings-link .nav-icon {
     color: #fff;
 }
+

+ 6 - 5
apps/options/index.html

@@ -226,13 +226,13 @@
                 <div class="sidebar-section">
                     <h4>工具分类</h4>
                     <ul class="category-list">
-                        <li :class="{active: currentCategory === ''}" 
+                        <li :class="{active: currentCategory === '' && currentView === 'all'}" 
                             @click="handleCategoryChange('')">
                             全部分类
                             <span class="count">({{Object.keys(originalTools).length}})</span>
                         </li>
                         <li v-for="category in categories" 
-                            :class="{active: currentCategory === category.key}"
+                            :class="{active: currentCategory === category.key && currentView === 'all'}"
                             @click="handleCategoryChange(category.key)">
                             {{category.name}}
                             <span class="count">({{getCategoryCount(category.key)}})</span>
@@ -242,15 +242,15 @@
                 <div class="sidebar-section">
                     <h4>我的工具</h4>
                     <ul class="my-tools">
-                        <li @click="showMyInstalled">
+                        <li :class="{active: currentView === 'installed'}" @click="showMyInstalled">
                             已安装
                             <span class="count">({{installedCount}})</span>
                         </li>
-                        <li @click="showMyFavorites">
+                        <li :class="{active: currentView === 'favorites'}" @click="showMyFavorites">
                             我的收藏
                             <span class="count">({{getFavoritesCount()}})</span>
                         </li>
-                        <li @click="showRecentUsed">
+                        <li :class="{active: currentView === 'recent'}" @click="showRecentUsed">
                             最近使用
                             <span class="count">({{recentCount}})</span>
                         </li>
@@ -303,3 +303,4 @@
 
 </body>
 </html> 
+

+ 5 - 1
apps/options/index.js

@@ -1191,7 +1191,10 @@ new Vue({
             this.currentView = 'recent';
             this.currentCategory = '';
             this.searchKey = '';
-            // recentUsed已在initData和getRecentUsedData中维护,activeTools会自动刷新
+            // 重新获取最近使用的工具数据
+            this.recentUsed = await Statistics.getRecentUsedTools(10);
+            this.recentCount = this.recentUsed.length;
+            // activeTools会通过currentView的watcher自动更新
         },
 
         handleRecommendClick(card) {
@@ -1278,3 +1281,4 @@ if (window.chrome && chrome.runtime && chrome.runtime.sendMessage) {
     Awesome.collectAndSendClientInfo();
 } 
 
+