-
-
{t('resultsWillShow')}
+ {/* 检测结果统计 - 始终显示,但在没有结果时显示0 */}
+
+
+ {/* 密钥列表区域 - 始终显示结果卡片 */}
+
+ {state.showLogTooltip && (
+
+
{t('results.logTooltip')}
+
+ )}
+
+ {/* Tab列表始终显示 */}
+
+
+
+ {(state.showResults || state.isTesting || state.keyResults.length > 0) ? (
+
+ ) : (
+
+
+
+
+ }
+ message={t('resultsWillShow')}
+ />
+ )}
- )}
+
+ {/* 复制按钮始终显示在底部 */}
+
+
diff --git a/src/components/features/RetryControl/RetryControl.module.css b/src/components/features/RetryControl/RetryControl.module.css
index 43b8be4..200f0a1 100644
--- a/src/components/features/RetryControl/RetryControl.module.css
+++ b/src/components/features/RetryControl/RetryControl.module.css
@@ -6,16 +6,11 @@
justify-content: space-between;
margin-top: 12px;
padding: 16px;
- background: #fff3cd;
- border: 2px solid #ffeaa7;
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
border-radius: 12px;
- transition: all 0.3s ease;
}
-.retryContainer:hover {
- border-color: #f39c12;
- background: #fef9e7;
-}
.retryInputSection {
flex-shrink: 0;
@@ -26,20 +21,20 @@
width: 80px !important;
text-align: center;
font-weight: 600;
- color: #f39c12 !important;
- background: white !important;
- border: 2px solid #ffeaa7 !important;
+ color: #495057 !important;
+ background: var(--bg-input) !important;
+ border: 1px solid var(--border-color) !important;
}
.retryInputSection .form-control:focus {
- border-color: #f39c12 !important;
- box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.1) !important;
+ border-color: var(--border-focus) !important;
+ box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1) !important;
}
.retryInputSection .form-control:disabled {
opacity: 0.6;
cursor: not-allowed;
- background: #f8f9fa !important;
+ background: var(--bg-tertiary) !important;
}
.retrySliderSection {
@@ -63,9 +58,8 @@
appearance: none;
height: 6px;
border-radius: 3px;
- background: #ffeaa7;
+ background: var(--border-color);
outline: none;
- transition: background 0.3s ease;
}
.retrySlider::-webkit-slider-thumb {
@@ -74,22 +68,17 @@
width: 18px;
height: 18px;
border-radius: 50%;
- background: #f39c12;
+ background: #495057;
cursor: pointer;
- transition: background 0.3s ease;
box-shadow: 0 2px 6px rgba(243, 156, 18, 0.3);
}
-.retrySlider::-webkit-slider-thumb:hover {
- background: #e67e22;
- box-shadow: 0 4px 12px rgba(243, 156, 18, 0.4);
-}
.retrySlider::-moz-range-thumb {
width: 18px;
height: 18px;
border-radius: 50%;
- background: #f39c12;
+ background: #495057;
cursor: pointer;
border: none;
box-shadow: 0 2px 6px rgba(243, 156, 18, 0.3);
@@ -112,12 +101,12 @@
min-width: 30px;
text-align: center;
font-weight: 700;
- color: #f39c12;
+ color: #495057;
font-size: clamp(14px, 2.5vw, 18px);
- background: white;
+ background: var(--bg-input);
padding: 4px 8px;
border-radius: 6px;
- border: 1px solid #ffeaa7;
+ border: 1px solid var(--border-color);
flex-shrink: 0;
}
@@ -139,7 +128,6 @@
cursor: pointer;
font-size: 12px;
font-weight: 500;
- transition: all 0.3s ease;
min-width: 60px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
flex: 1;
@@ -147,15 +135,9 @@
text-align: center;
}
-.retryPresetBtn:hover:not(:disabled) {
- background: #f39c12;
- color: white;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(243, 156, 18, 0.3);
-}
.retryPresetBtn.active {
- background: #f39c12;
+ background: #e8eaed;
color: white;
box-shadow: 0 4px 12px rgba(243, 156, 18, 0.4);
}
@@ -163,51 +145,43 @@
.retryPresetBtn:disabled {
opacity: 0.6;
cursor: not-allowed;
- transform: none !important;
}
-/* 深色主题 - 修改为 #2A2A2A */
+/* 深色主题 */
:global(.dark-theme) .retryContainer {
- background: #2A2A2A;
- border-color: #5d4e23;
+ background: var(--bg-card);
+ border-color: var(--border-color);
}
-:global(.dark-theme) .retryContainer:hover {
- border-color: #d68910;
- background: #323232;
-}
:global(.dark-theme) .retryInputSection .form-control {
- background: #1e1e1e !important;
- color: #d68910 !important;
- border-color: #5d4e23 !important;
+ background: var(--bg-input) !important;
+ color: #ffffff !important;
+ border-color: var(--border-color) !important;
}
:global(.dark-theme) .retryInputSection .form-control:focus {
- border-color: #d68910 !important;
- box-shadow: 0 0 0 3px rgba(214, 137, 16, 0.1) !important;
+ border-color: var(--border-focus) !important;
+ box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.1) !important;
}
:global(.dark-theme) .retrySlider {
- background: #5d4e23;
+ background: var(--border-color);
}
:global(.dark-theme) .retrySlider::-webkit-slider-thumb {
- background: #d68910;
+ background: #e8eaed;
}
-:global(.dark-theme) .retrySlider::-webkit-slider-thumb:hover {
- background: #b7791f;
-}
:global(.dark-theme) .retrySlider::-moz-range-thumb {
- background: #d68910;
+ background: #e8eaed;
}
:global(.dark-theme) .retrySliderValue {
- color: #d68910;
- background: #1e1e1e;
- border-color: #5d4e23;
+ color: #e8eaed;
+ background: var(--bg-input);
+ border-color: var(--border-color);
}
:global(.dark-theme) .retryPresetBtn {
@@ -217,14 +191,9 @@
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
-:global(.dark-theme) .retryPresetBtn:hover:not(:disabled) {
- background: #d68910;
- color: white;
- box-shadow: 0 4px 12px rgba(214, 137, 16, 0.3);
-}
:global(.dark-theme) .retryPresetBtn.active {
- background: #d68910;
+ background: #e8eaed;
color: white;
box-shadow: 0 4px 12px rgba(214, 137, 16, 0.4);
}
diff --git a/src/components/features/RetryControl/index.jsx b/src/components/features/RetryControl/index.jsx
index 8d6999b..881e06b 100644
--- a/src/components/features/RetryControl/index.jsx
+++ b/src/components/features/RetryControl/index.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import { useLanguage } from '../../../hooks/useLanguage';
import { useAppState } from '../../../contexts/AppStateContext';
+import FormField from '../../common/FormField';
import styles from './RetryControl.module.css';
const RetryControl = () => {
@@ -20,35 +21,18 @@ const RetryControl = () => {
dispatch({ type: 'SET_RETRY_COUNT', payload: value });
};
- const handlePresetClick = (value) => {
- dispatch({ type: 'SET_RETRY_COUNT', payload: value });
- };
-
- const presets = [
- { value: 0, key: 'noRetry' },
- { value: 2, key: 'lightRetry' },
- { value: 3, key: 'normalRetry' },
- { value: 5, key: 'heavyRetry' }
- ];
return (
-
-
+
{t('retryHelp')}}
+ >
- {t('retryHelp')}
-
+
);
};
diff --git a/src/components/layout/AppLayout/AppLayout.module.css b/src/components/layout/AppLayout/AppLayout.module.css
index cdec310..96184fb 100644
--- a/src/components/layout/AppLayout/AppLayout.module.css
+++ b/src/components/layout/AppLayout/AppLayout.module.css
@@ -38,10 +38,9 @@
flex-direction: column;
}
-/* 双栏布局 - 确保两列完全等高 */
+/* 双栏布局 - 使用flex布局确保两列完全等高 */
.twoColumnLayout {
- display: grid;
- grid-template-columns: 1fr 1fr;
+ display: flex;
gap: var(--spacing-lg);
flex: 1;
min-height: 0;
@@ -50,6 +49,7 @@
.leftColumn,
.rightColumn {
+ flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
@@ -59,7 +59,7 @@
/* 响应式设计 */
@media (max-width: 992px) {
.twoColumnLayout {
- grid-template-columns: 1fr;
+ flex-direction: column;
gap: var(--spacing-md);
}
}
diff --git a/src/components/layout/AppLayout/index.jsx b/src/components/layout/AppLayout/index.jsx
index ec183bc..a61ccb2 100644
--- a/src/components/layout/AppLayout/index.jsx
+++ b/src/components/layout/AppLayout/index.jsx
@@ -36,8 +36,14 @@ const AppLayout = ({ children }) => {
}
};
+ // 同时监听鼠标和触摸事件,确保移动端兼容性
document.addEventListener('mousedown', handleClickOutside);
- return () => document.removeEventListener('mousedown', handleClickOutside);
+ document.addEventListener('touchstart', handleClickOutside);
+
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ document.removeEventListener('touchstart', handleClickOutside);
+ };
}, [isSidebarCollapsed]);
return (
diff --git a/src/components/layout/NavBar/NavBar.module.css b/src/components/layout/NavBar/NavBar.module.css
index 4fe8853..e59826f 100644
--- a/src/components/layout/NavBar/NavBar.module.css
+++ b/src/components/layout/NavBar/NavBar.module.css
@@ -36,21 +36,12 @@
border-radius: 6px;
cursor: pointer;
color: var(--text-secondary);
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
justify-content: center;
}
-.sidebarToggle:hover {
- background: rgba(175, 184, 193, 0.12);
- color: var(--text-primary);
- transform: translateY(-0.5px);
-}
-.sidebarToggle:active {
- transform: scale(0.95) translateY(0);
-}
/* Brand Section */
.brandSection {
@@ -84,18 +75,9 @@
border: none;
cursor: pointer;
color: var(--text-secondary);
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
-.actionBtn:hover {
- background: rgba(175, 184, 193, 0.12);
- color: var(--text-primary);
- transform: translateY(-0.5px);
-}
-.actionBtn:active {
- transform: scale(0.95) translateY(0);
-}
.githubLink {
display: flex;
@@ -105,7 +87,6 @@
height: 100%;
color: inherit;
text-decoration: none;
- transition: inherit;
}
/* Language/Theme Combobox */
@@ -121,33 +102,16 @@
font-size: var(--font-size-base);
font-weight: 500;
cursor: pointer;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
-.comboboxBtn:hover {
- background: rgba(175, 184, 193, 0.12);
- color: var(--text-primary);
- transform: translateY(-0.5px);
-}
-.comboboxBtn:active {
- transform: scale(0.98) translateY(0);
-}
.chevron {
opacity: 0.5;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
-.comboboxBtn:hover .chevron {
- opacity: 0.7;
-}
/* Theme Icons */
-.sunIcon,
-.moonIcon {
- transition: all 0.3s ease;
-}
.sunIcon.visible,
.moonIcon.visible {
@@ -176,20 +140,8 @@
overflow: hidden;
z-index: 1001;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
- animation: dropdownFadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
-@keyframes dropdownFadeIn {
- from {
- opacity: 0;
- transform: translateY(-4px) scale(0.98);
- }
-
- to {
- opacity: 1;
- transform: translateY(0) scale(1);
- }
-}
.dropdownItem {
display: flex;
@@ -203,22 +155,14 @@
font-size: var(--font-size-base);
cursor: pointer;
text-align: left;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
-.dropdownItem:hover {
- background: rgba(175, 184, 193, 0.1);
- transform: translateX(2px);
-}
.dropdownItem.active {
color: var(--color-primary);
background: rgba(9, 105, 218, 0.08);
}
-.dropdownItem.active:hover {
- background: rgba(9, 105, 218, 0.12);
-}
.themeItem {
display: flex;
@@ -238,33 +182,18 @@
border-bottom-color: #444444;
}
-:global(.dark-theme) .sidebarToggle:hover {
- background: rgba(110, 118, 129, 0.12);
-}
-:global(.dark-theme) .actionBtn:hover {
- background: rgba(110, 118, 129, 0.12);
-}
-:global(.dark-theme) .comboboxBtn:hover {
- background: rgba(110, 118, 129, 0.12);
-}
:global(.dark-theme) .dropdownMenu {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
-:global(.dark-theme) .dropdownItem:hover {
- background: rgba(110, 118, 129, 0.1);
-}
:global(.dark-theme) .dropdownItem.active {
background: rgba(88, 166, 255, 0.1);
}
-:global(.dark-theme) .dropdownItem.active:hover {
- background: rgba(88, 166, 255, 0.15);
-}
/* 响应式 */
@media (max-width: 768px) {
@@ -292,12 +221,6 @@
font-size: 13px;
}
- /* 移动端减少悬浮效果 */
- .sidebarToggle:hover,
- .actionBtn:hover,
- .comboboxBtn:hover {
- transform: translateY(-0.25px);
- }
}
@media (max-width: 480px) {
@@ -318,21 +241,4 @@
/* 减少动画在低性能设备上的影响 */
@media (prefers-reduced-motion: reduce) {
- .sidebarToggle,
- .actionBtn,
- .comboboxBtn,
- .dropdownItem {
- transition: background-color 0.1s ease;
- }
-
- .sidebarToggle:hover,
- .actionBtn:hover,
- .comboboxBtn:hover,
- .dropdownItem:hover {
- transform: none;
- }
-
- .dropdownMenu {
- animation: none;
- }
}
\ No newline at end of file
diff --git a/src/components/layout/Sidebar/Sidebar.module.css b/src/components/layout/Sidebar/Sidebar.module.css
index e8dae92..a5594af 100644
--- a/src/components/layout/Sidebar/Sidebar.module.css
+++ b/src/components/layout/Sidebar/Sidebar.module.css
@@ -9,10 +9,7 @@
left: 0;
top: 60px;
z-index: 999;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
-
- /* PC端展开时添加阴影效果 */
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
}
@@ -42,7 +39,6 @@
padding: 8px 12px;
border-radius: 6px;
cursor: pointer;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
gap: 12px;
min-height: 36px;
justify-content: flex-start;
@@ -67,8 +63,6 @@
background: rgba(175, 184, 193, 0.12);
border-color: rgba(175, 184, 193, 0.2);
color: var(--text-primary);
- transform: translateY(-0.5px);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}
/* GitHub风格的选中状态 - 无左侧指示条 */
@@ -91,16 +85,13 @@
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.3);
}
-:global(.dark-theme) .sidebar.collapsed {
- box-shadow: none;
-}
-
:global(.dark-theme) .apiProvider:hover:not(.active) {
background: rgba(110, 118, 129, 0.12);
border-color: rgba(110, 118, 129, 0.2);
color: var(--text-primary);
}
+
:global(.dark-theme) .apiProvider.active {
background: linear-gradient(135deg,
rgba(110, 118, 129, 0.12) 0%,
@@ -119,7 +110,6 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 0.7;
}
@@ -127,7 +117,6 @@
.apiProvider:hover .providerIcon,
.apiProvider.active .providerIcon {
opacity: 1;
- transform: scale(1.05);
}
.providerName {
@@ -135,7 +124,6 @@
font-size: inherit;
white-space: nowrap;
overflow: hidden;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
opacity: 0.9;
letter-spacing: -0.01em;
}
@@ -145,6 +133,7 @@
opacity: 1;
}
+
/* 折叠时隐藏提供商名称 */
.sidebar.collapsed .providerName {
opacity: 0;
@@ -164,12 +153,12 @@
border-right: 1px solid var(--border-color);
flex-direction: column;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
}
- /* 移动端折叠时完全隐藏 */
+ /* 移动端折叠时完全收缩到屏幕外 */
.sidebar.collapsed {
- transform: translateX(-160px);
- width: 160px;
+ transform: translateX(-100%);
box-shadow: none;
}
@@ -183,15 +172,6 @@
}
/* 减少动画在低性能设备上的影响 */
-@media (prefers-reduced-motion: reduce) {
-
- .apiProvider,
- .providerIcon,
- .providerName,
- .sidebar {
- transition: none;
- }
-}
/* 为高对比度模式提供更好的可访问性 */
@media (prefers-contrast: high) {
@@ -215,4 +195,12 @@
:global(.dark-theme) .apiProvider:focus {
outline-color: #58a6ff;
+}
+
+/* 为请求减少动画的用户禁用过渡效果 */
+@media (prefers-reduced-motion: reduce) {
+ .sidebar,
+ .sidebar.collapsed {
+ transition: none !important;
+ }
}
\ No newline at end of file
diff --git a/src/components/layout/ThemeToggle/ThemeToggle.module.css b/src/components/layout/ThemeToggle/ThemeToggle.module.css
deleted file mode 100644
index 0515c86..0000000
--- a/src/components/layout/ThemeToggle/ThemeToggle.module.css
+++ /dev/null
@@ -1,180 +0,0 @@
-.themeControls {
- position: fixed;
- top: 10px;
- right: 10px;
- display: flex;
- gap: 8px;
- z-index: 1000;
-}
-
-/* GitHub Button */
-.githubBtn {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 36px;
- height: 36px;
- border-radius: 6px;
- background: rgba(255, 255, 255, 0.9);
- color: #333;
- text-decoration: none;
- transition: all 0.2s ease;
- border: 1px solid rgba(0, 0, 0, 0.1);
- backdrop-filter: blur(10px);
-}
-
-.githubBtn:hover {
- background: rgba(255, 255, 255, 1);
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-}
-
-/* Dropdown */
-.dropdown {
- position: relative;
-}
-
-.dropdownBtn {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 6px 12px;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 6px;
- background: rgba(255, 255, 255, 0.9);
- color: #333;
- font-size: 14px;
- cursor: pointer;
- transition: all 0.2s ease;
- backdrop-filter: blur(10px);
- min-width: 120px;
-}
-
-.dropdownBtn:hover {
- background: rgba(255, 255, 255, 1);
- transform: translateY(-2px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-}
-
-.dropdownBtn .chevron {
- margin-left: auto;
- transition: transform 0.2s ease;
-}
-
-.dropdownBtn:hover .chevron {
- transform: rotate(180deg);
-}
-
-/* Dropdown Menu */
-.dropdownMenu {
- position: absolute;
- top: calc(100% + 4px);
- right: 0;
- min-width: 140px;
- background: rgba(255, 255, 255, 0.95);
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 6px;
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
- backdrop-filter: blur(20px);
- overflow: hidden;
- z-index: 1001;
-}
-
-.dropdownItem {
- display: flex;
- align-items: center;
- gap: 8px;
- width: 100%;
- padding: 8px 12px;
- border: none;
- background: none;
- color: #333;
- font-size: 14px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- text-align: left;
-}
-
-.dropdownItem:hover {
- background: rgba(0, 0, 0, 0.05);
-}
-
-.dropdownItem.active {
- background: rgba(102, 126, 234, 0.1);
- color: #667eea;
-}
-
-.dropdownItem.active svg {
- color: #667eea;
-}
-
-/* Dark Theme Styles */
-:global(.dark-theme) .githubBtn {
- background: rgba(0, 0, 0, 0.9);
- color: #fff;
- border-color: rgba(255, 255, 255, 0.1);
-}
-
-:global(.dark-theme) .githubBtn:hover {
- background: rgba(0, 0, 0, 1);
- box-shadow: 0 4px 12px rgba(255, 255, 255, 0.1);
-}
-
-:global(.dark-theme) .dropdownBtn {
- background: rgba(0, 0, 0, 0.9);
- color: #fff;
- border-color: rgba(255, 255, 255, 0.1);
-}
-
-:global(.dark-theme) .dropdownBtn:hover {
- background: rgba(0, 0, 0, 1);
- box-shadow: 0 4px 12px rgba(255, 255, 255, 0.1);
-}
-
-:global(.dark-theme) .dropdownMenu {
- background: rgba(0, 0, 0, 0.95);
- border-color: rgba(255, 255, 255, 0.1);
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
-}
-
-:global(.dark-theme) .dropdownItem {
- color: #fff;
-}
-
-:global(.dark-theme) .dropdownItem:hover {
- background: rgba(255, 255, 255, 0.05);
-}
-
-:global(.dark-theme) .dropdownItem.active {
- background: rgba(102, 126, 234, 0.2);
- color: #667eea;
-}
-
-/* Mobile Responsive */
-@media (max-width: 768px) {
- .themeControls {
- top: 8px;
- right: 8px;
- gap: 6px;
- }
-
- .githubBtn {
- width: 32px;
- height: 32px;
- }
-
- .dropdownBtn {
- padding: 4px 8px;
- font-size: 12px;
- min-width: 100px;
- }
-
- .dropdownMenu {
- min-width: 120px;
- }
-
- .dropdownItem {
- padding: 6px 8px;
- font-size: 12px;
- }
-}
\ No newline at end of file
diff --git a/src/components/layout/ThemeToggle/index.jsx b/src/components/layout/ThemeToggle/index.jsx
deleted file mode 100644
index 298f9e6..0000000
--- a/src/components/layout/ThemeToggle/index.jsx
+++ /dev/null
@@ -1,159 +0,0 @@
-import React, { useState, useEffect, useRef } from 'react';
-import { useTheme } from '../../../hooks/useTheme';
-import { useLanguage } from '../../../hooks/useLanguage';
-import styles from './ThemeToggle.module.css';
-
-const ThemeToggle = () => {
- const { theme, toggleTheme } = useTheme();
- const { language, toggleLanguage, t } = useLanguage();
- const [showLanguageMenu, setShowLanguageMenu] = useState(false);
- const [showThemeMenu, setShowThemeMenu] = useState(false);
- const languageRef = useRef(null);
- const themeRef = useRef(null);
-
- // Close dropdowns when clicking outside
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (languageRef.current && !languageRef.current.contains(event.target)) {
- setShowLanguageMenu(false);
- }
- if (themeRef.current && !themeRef.current.contains(event.target)) {
- setShowThemeMenu(false);
- }
- };
-
- document.addEventListener('mousedown', handleClickOutside);
- return () => document.removeEventListener('mousedown', handleClickOutside);
- }, []);
-
- return (
-
- {/* GitHub Icon */}
-
-
-
-
- {/* Language Selector */}
-
-
- {showLanguageMenu && (
-
-
-
-
- )}
-
-
- {/* Theme Toggle */}
-
-
- {showThemeMenu && (
-
-
-
-
-
- )}
-
-
- );
-};
-
-export default ThemeToggle;
diff --git a/src/contexts/AppStateContext.jsx b/src/contexts/AppStateContext.jsx
index 87ef930..77f7dc1 100644
--- a/src/contexts/AppStateContext.jsx
+++ b/src/contexts/AppStateContext.jsx
@@ -108,6 +108,9 @@ const getInitialState = () => {
// Gemini付费检测 - 从localStorage获取
enablePaidDetection: localStorage.getItem('enablePaidDetection') ? JSON.parse(localStorage.getItem('enablePaidDetection')) : false,
+ // 日志显示控制 - 从localStorage获取,默认关闭
+ showDetailedLogs: localStorage.getItem('showDetailedLogs') ? JSON.parse(localStorage.getItem('showDetailedLogs')) : false,
+
// 测试状态
isTesting: false,
detectedModels: new Set(),
@@ -130,6 +133,7 @@ const getInitialState = () => {
activeLogKey: null,
isLogModalOpen: false,
enablePaidDetection: false,
+ showDetailedLogs: false,
isTesting: false,
keyResults: [],
showResults: false,
@@ -201,6 +205,12 @@ const appReducer = (state, action) => {
model: action.payload ? 'gemini-2.5-flash' : state.model
};
+ case 'SET_SHOW_DETAILED_LOGS':
+ return {
+ ...state,
+ showDetailedLogs: action.payload
+ };
+
case 'START_TESTING':
return {
...state,
@@ -406,11 +416,12 @@ export const AppStateProvider = ({ children }) => {
localStorage.setItem('concurrency', JSON.stringify(state.concurrency));
localStorage.setItem('maxRetries', JSON.stringify(state.retryCount));
localStorage.setItem('enablePaidDetection', JSON.stringify(state.enablePaidDetection));
+ localStorage.setItem('showDetailedLogs', JSON.stringify(state.showDetailedLogs));
localStorage.setItem('hasSeenLogTooltip', JSON.stringify(state.hasSeenLogTooltip));
} catch (error) {
console.warn('保存全局配置到本地存储失败:', error);
}
- }, [state.apiType, state.concurrency, state.retryCount, state.enablePaidDetection, state.hasSeenLogTooltip]);
+ }, [state.apiType, state.concurrency, state.retryCount, state.enablePaidDetection, state.showDetailedLogs, state.hasSeenLogTooltip]);
// 监听API状态变化并防抖保存(避免频繁保存,如输入时的每个字符变化)
useEffect(() => {
@@ -478,7 +489,7 @@ export const AppStateProvider = ({ children }) => {
const collector = getLogCollector();
if (collector) {
if (typeof collector.setEnabled === 'function') {
- collector.setEnabled(true);
+ collector.setEnabled(state.showDetailedLogs);
}
if (typeof collector.hydrateLogs === 'function' && (stateRef.current.logs || []).length > 0) {
collector.hydrateLogs(stateRef.current.logs || []);
@@ -488,7 +499,14 @@ export const AppStateProvider = ({ children }) => {
} catch (error) {
// 安静失败,不影响主要功能
}
- }, [dispatch]);
+ }, [dispatch, state.showDetailedLogs]);
+
+ // 监听日志开关状态变化,关闭时清空日志
+ useEffect(() => {
+ if (!state.showDetailedLogs && (state.logs || []).length > 0) {
+ dispatch({ type: 'CLEAR_LOGS' });
+ }
+ }, [state.showDetailedLogs, dispatch]);
const value = {
state,
diff --git a/src/hooks/useVirtualization.js b/src/hooks/useVirtualization.js
index fb884b4..f655772 100644
--- a/src/hooks/useVirtualization.js
+++ b/src/hooks/useVirtualization.js
@@ -1,54 +1,15 @@
import { useCallback } from 'react';
export const useVirtualization = () => {
- const getItemHeight = useCallback((keyData, apiType) => {
- if (!keyData) return 60; // 默认高度
-
- // 基础高度:padding(12*2=24) + wrapper padding(2*2=4) + 基础内容(40) = 68px
- let baseHeight = 60;
-
- // 计算密钥长度对高度的影响
- const keyLength = keyData.key ? keyData.key.length : 0;
- if (keyLength > 60) {
- // 长密钥需要更多行来显示
- const extraLines = Math.ceil((keyLength - 60) / 60);
- baseHeight += extraLines * 18; // 每行约18px
- }
-
- // 每行额外内容的高度
- const lineHeight = 16;
-
- // 如果有模型信息,增加一行
- if (keyData.model) {
- baseHeight += lineHeight;
- }
-
- // 如果有错误信息,增加一行(错误信息可能较长)
- if (keyData.error) {
- const errorLength = keyData.error.length;
- if (errorLength > 50) {
- baseHeight += lineHeight * 2; // 长错误信息占两行
- } else {
- baseHeight += lineHeight;
- }
+ const getItemHeight = useCallback(() => {
+ // 根据屏幕大小返回固定高度
+ if (window.matchMedia && window.matchMedia('(max-width: 480px)').matches) {
+ return 62; // 超小屏幕:60px + wrapper padding(2px)
+ } else if (window.matchMedia && window.matchMedia('(max-width: 768px)').matches) {
+ return 66; // 移动端:64px + wrapper padding(2px)
+ } else {
+ return 74; // 桌面端:72px + wrapper padding(2px)
}
-
- // 如果有重试信息,增加一行
- if (keyData.retryCount > 0) {
- baseHeight += lineHeight;
- }
-
- // 如果有状态信息(有效密钥信息),增加一行
- if (keyData.status === 'valid' || keyData.status === 'paid') {
- baseHeight += lineHeight;
- }
-
- // 如果是硅基流动且是有效密钥,为余额显示增加额外高度
- if (apiType === 'siliconcloud' && (keyData.status === 'valid' || keyData.status === 'paid')) {
- baseHeight += lineHeight; // 为余额显示增加一行高度
- }
-
- return Math.max(baseHeight, 68); // 设置最小高度为68px
}, []);
return {
diff --git a/src/locales/en.json b/src/locales/en.json
index 66706c5..ddcef0d 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -3,24 +3,14 @@
"selectModel": "Test Model",
"customModel": "Custom",
"presetModel": "Preset",
- "modelHelp": "Choose preset model or enter custom model name",
"modelInputPlaceholder": "Enter custom model name",
"detectedModelsTitle": "Detected Models",
"detecting": "Detecting...",
"detected": "Detected",
"proxyUrl": "Proxy Server URL (Optional)",
- "proxyHelp": "Leave empty to use default proxy",
"concurrencyControl": "Concurrency Control",
"retryControl": "Retry Control",
"retryHelp": "Number of retries when encountering temporary errors (like 403), helps improve detection accuracy",
- "slow": "Slow",
- "normal": "Normal",
- "fast": "Fast",
- "ultra": "Ultra",
- "noRetry": "No Retry",
- "lightRetry": "Light",
- "normalRetry": "Normal",
- "heavyRetry": "Heavy",
"apiKeys": "API Key List (one per line)",
"apiKeysPlaceholder": "Enter API keys, one per line:\nsk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nsk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n...",
"import": "Import",
@@ -213,5 +203,7 @@
"email": "Email",
"fetchFailed": "Query Failed",
"clickToRefresh": "Click refresh button to query balance information"
- }
+ },
+ "showDetailedLogs": "Show Detailed Logs",
+ "showDetailedLogsDescription": "Control whether to show detailed API call logs"
}
diff --git a/src/locales/zh.json b/src/locales/zh.json
index e77aa47..acc3217 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -3,24 +3,14 @@
"selectModel": "测试模型",
"customModel": "自定义",
"presetModel": "预设",
- "modelHelp": "可以选择预设模型或输入自定义模型名",
"modelInputPlaceholder": "输入自定义模型名",
"detectedModelsTitle": "检测到的模型",
"detecting": "检测中",
"detected": "检测到",
"proxyUrl": "代理服务器 URL (可选)",
- "proxyHelp": "留空使用默认代理",
"concurrencyControl": "并发控制",
"retryControl": "重试控制",
"retryHelp": "遇到临时错误(如403)时重试次数,有助于提高检测准确性",
- "slow": "慢速",
- "normal": "正常",
- "fast": "快速",
- "ultra": "极速",
- "noRetry": "不重试",
- "lightRetry": "轻度",
- "normalRetry": "正常",
- "heavyRetry": "重度",
"apiKeys": "API 密钥列表 (每行一个)",
"apiKeysPlaceholder": "请输入API密钥,每行一个:\nsk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nsk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n...",
"import": "导入",
@@ -213,5 +203,7 @@
"email": "邮箱",
"fetchFailed": "查询失败",
"clickToRefresh": "点击刷新按钮查询余额信息"
- }
+ },
+ "showDetailedLogs": "显示详细日志",
+ "showDetailedLogsDescription": "控制是否显示API调用的详细日志信息"
}
diff --git a/src/styles/components.css b/src/styles/components.css
index 100c40b..4236723 100644
--- a/src/styles/components.css
+++ b/src/styles/components.css
@@ -15,7 +15,6 @@
font-weight: 500;
line-height: 1;
cursor: pointer;
- transition: all var(--transition-fast);
text-decoration: none;
user-select: none;
}
@@ -23,7 +22,6 @@
.btn-base:disabled {
opacity: 0.6;
cursor: not-allowed;
- transform: none !important;
}
/* 按钮变体 */
@@ -33,49 +31,24 @@
border-color: var(--color-primary);
}
-.btn-primary:hover:not(:disabled) {
- background: #0056b3;
- border-color: #0056b3;
- transform: translateY(-1px);
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
.btn-secondary {
background: #6c757d;
color: white;
border-color: #6c757d;
}
-.btn-secondary:hover:not(:disabled) {
- background: #5a6268;
- border-color: #5a6268;
- transform: translateY(-1px);
-}
-
.btn-ghost {
background: white;
color: var(--text-secondary);
border-color: var(--border-color);
}
-.btn-ghost:hover:not(:disabled) {
- background: var(--bg-card);
- color: var(--text-primary);
- border-color: var(--border-color);
-}
-
.btn-danger {
background: var(--color-danger);
color: white;
border-color: var(--color-danger);
}
-.btn-danger:hover:not(:disabled) {
- background: #c82333;
- border-color: #c82333;
- transform: translateY(-1px);
-}
-
/* 按钮尺寸 */
.btn-sm {
padding: var(--spacing-xs) var(--spacing-sm);
@@ -121,12 +94,6 @@
border: 1px solid var(--border-color);
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-xs);
- transition: all var(--transition-normal);
-}
-
-.card-hover:hover {
- transform: translateY(-2px);
- box-shadow: var(--shadow-md);
}
.card-padding {
@@ -146,11 +113,10 @@
background: var(--bg-input);
color: var(--text-primary);
font-size: var(--font-size-sm);
- transition: border-color var(--transition-fast);
}
/* 只对textarea类型的form-field应用特殊样式 */
-.form-field.textarea,
+.form-field.textarea,
textarea.form-field {
resize: vertical;
min-height: 120px;
@@ -239,7 +205,6 @@ textarea.form-field {
bottom: 0;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
- transition: var(--transition-fast);
border-radius: 12px;
}
@@ -251,21 +216,20 @@ textarea.form-field {
left: 2px;
bottom: 2px;
background: var(--text-secondary);
- transition: var(--transition-fast);
border-radius: 50%;
}
-.switch-input:checked + .switch-slider {
+.switch-input:checked+.switch-slider {
background: var(--primary-color);
border-color: var(--primary-color);
}
-.switch-input:focus + .switch-slider {
+.switch-input:focus+.switch-slider {
box-shadow: 0 0 0 2px var(--primary-color-alpha);
}
-.switch-input:checked + .switch-slider:before {
- transform: translateX(20px);
+.switch-input:checked+.switch-slider:before {
+ left: 22px;
background: white;
}
@@ -301,11 +265,6 @@ textarea.form-field {
border: 2px solid var(--border-color);
border-radius: 50%;
border-top-color: var(--primary-color);
- animation: spin 1s ease-in-out infinite;
-}
-
-@keyframes spin {
- to { transform: rotate(360deg); }
}
/* 工具提示 */
@@ -314,22 +273,6 @@ textarea.form-field {
cursor: help;
}
-.tooltip:hover::after {
- content: attr(data-tooltip);
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- background: var(--bg-tooltip);
- color: var(--text-tooltip);
- padding: var(--spacing-xs) var(--spacing-sm);
- border-radius: var(--border-radius);
- font-size: var(--font-size-xs);
- white-space: nowrap;
- z-index: 1000;
- box-shadow: var(--shadow-md);
-}
-
/* 控制按钮容器 */
.controls-container {
display: flex;
@@ -353,11 +296,11 @@ textarea.form-field {
.mobile-hidden {
display: none !important;
}
-
+
.mobile-full-width {
width: 100% !important;
}
-
+
.mobile-stack {
flex-direction: column !important;
}
@@ -370,34 +313,18 @@ textarea.form-field {
border-color: var(--border-color);
}
-.dark-theme .btn-ghost:hover:not(:disabled) {
- background: var(--bg-hover);
- color: var(--text-primary);
- border-color: var(--border-color);
-}
-
.dark-theme .btn-secondary {
background: #5a6268;
color: white;
border-color: #5a6268;
}
-.dark-theme .btn-secondary:hover:not(:disabled) {
- background: #484e53;
- border-color: #484e53;
-}
-
.dark-theme .btn-primary {
background: var(--color-primary);
color: white;
border-color: var(--color-primary);
}
-.dark-theme .btn-primary:hover:not(:disabled) {
- background: #0056b3;
- border-color: #0056b3;
-}
-
/* 暗色主题开关样式 */
.dark-theme .switch-slider {
background: var(--bg-secondary);
@@ -408,15 +335,195 @@ textarea.form-field {
background: var(--text-secondary);
}
-.dark-theme .switch-input:checked + .switch-slider {
+.dark-theme .switch-input:checked+.switch-slider {
background: var(--primary-color);
border-color: var(--primary-color);
}
-.dark-theme .switch-input:focus + .switch-slider {
+.dark-theme .switch-input:focus+.switch-slider {
box-shadow: 0 0 0 2px var(--primary-color-alpha);
}
-.dark-theme .switch-input:checked + .switch-slider:before {
+.dark-theme .switch-input:checked+.switch-slider:before {
background: white;
}
+
+/* ==========================================================================
+ 扩展卡片变体 - 统一命名规范
+ ========================================================================== */
+
+/* 主要功能卡片 */
+.card--primary {
+ background: var(--bg-card);
+ padding: var(--spacing-md);
+ border-radius: var(--border-radius);
+ border: 1px solid var(--border-color);
+ margin-bottom: var(--spacing-md);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+/* 信息提示卡片 */
+.card--info {
+ background: #e3f2fd;
+ border-color: #bbdefb;
+ color: #1976d2;
+ padding: var(--spacing-sm) var(--spacing-md);
+}
+
+/* 结果展示卡片 */
+.card--results {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ margin-bottom: 0;
+ background: #f8f9fa;
+ border: 2px solid #e9ecef;
+ border-radius: 12px;
+ padding: 16px;
+ max-height: 340px;
+ min-height: 340px;
+}
+
+/* 结果内容区域 */
+.results-content {
+ border: 1px solid var(--border-color);
+ border-top: none;
+ border-radius: 0 0 6px 6px;
+ background-color: var(--bg-input);
+ min-height: 200px;
+ display: flex;
+ flex-direction: column;
+}
+
+/* 空状态卡片 */
+.card--empty-state {
+ background: var(--bg-card);
+ padding: var(--spacing-md);
+ border-radius: var(--border-radius);
+ border: 1px solid var(--border-color);
+ margin-bottom: var(--spacing-md);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+/* 设置按钮样式 */
+.btn--settings {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ width: 100%;
+ min-height: 48px;
+ padding: var(--spacing-md) var(--spacing-xl);
+ background: var(--color-secondary);
+ color: white;
+ border: none;
+ border-radius: var(--border-radius);
+ font-size: var(--font-size-base);
+ font-weight: 600;
+ cursor: pointer;
+ text-decoration: none;
+ box-sizing: border-box;
+ margin-bottom: 0;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+/* 深色主题适配 */
+.dark-theme .card--primary {
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+}
+
+.dark-theme .card--info {
+ background: var(--bg-card);
+ border-color: var(--border-color);
+ color: var(--text-primary);
+}
+
+.dark-theme .card--results {
+ background: #2a2a2a;
+ border-color: #444444;
+}
+
+.dark-theme .card--empty-state {
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+}
+
+.dark-theme .btn--settings {
+ background: var(--color-secondary);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+}
+
+/* 响应式适配 */
+@media (max-width: 768px) {
+ .card--primary {
+ padding: var(--spacing-sm);
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
+ }
+
+ .card--info {
+ padding: var(--spacing-xs) var(--spacing-sm);
+ }
+
+ .card--empty-state {
+ padding: var(--spacing-sm);
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
+ }
+
+ .btn--settings {
+ min-height: 40px;
+ font-size: 14px;
+ padding: var(--spacing-sm) var(--spacing-md);
+ }
+
+ .card--results {
+ max-height: 400px;
+ min-height: 400px;
+ padding: 12px;
+ }
+}
+
+@media (max-width: 480px) {
+ .card--results {
+ max-height: 350px;
+ min-height: 350px;
+ padding: 10px;
+ }
+}
+
+/* 兼容性别名 - 逐步废弃 */
+.function-card {
+ background: var(--bg-card);
+ padding: var(--spacing-md);
+ border-radius: var(--border-radius);
+ border: 1px solid var(--border-color);
+ margin-bottom: var(--spacing-md);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.usage-card {
+ background: #e3f2fd;
+ border-color: #bbdefb;
+ color: #1976d2;
+ padding: var(--spacing-sm) var(--spacing-md);
+}
+
+.results-card {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ margin-bottom: 0;
+ background: #f8f9fa;
+ border: 2px solid #e9ecef;
+ border-radius: 12px;
+ padding: 16px;
+ max-height: 392px;
+ min-height: 392px;
+}
+
+.initial-empty-state-card {
+ background: var(--bg-card);
+ padding: var(--spacing-md);
+ border-radius: var(--border-radius);
+ border: 1px solid var(--border-color);
+ margin-bottom: var(--spacing-md);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
\ No newline at end of file
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 2fa1fca..b1b38b2 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -79,11 +79,6 @@ body {
border-color: var(--color-success);
}
-.btn-success:hover:not(:disabled) {
- background: #1e7e34;
- border-color: #1e7e34;
- transform: translateY(-1px);
-}
/* 基础卡片样式 */
.function-card {
@@ -93,54 +88,10 @@ body {
border: 1px solid var(--border-color);
margin-bottom: var(--spacing-md);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- transition: box-shadow 0.3s ease, transform 0.2s ease;
}
-.function-card:hover {
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
- transform: translateY(-2px);
-}
-/* 高级设置按钮样式 */
-.settings-card {
- padding: 0;
- background: none;
- border: none;
- margin-bottom: var(--spacing-md);
- box-shadow: none;
-}
-.settings-card:hover {
- box-shadow: none;
- transform: none;
-}
-
-.settings-button {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- width: 100%;
- min-height: 48px;
- padding: var(--spacing-md) var(--spacing-xl);
- background: var(--color-secondary);
- color: white;
- border: none;
- border-radius: var(--border-radius);
- font-size: var(--font-size-base);
- font-weight: 600;
- cursor: pointer;
- text-decoration: none;
- box-sizing: border-box;
- margin-bottom: 0;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- transition: all 0.3s ease;
-}
-
-.settings-button:hover {
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
- transform: translateY(-2px);
-}
/* 使用说明卡片样式 */
.usage-card {
@@ -193,13 +144,8 @@ body {
flex-direction: column;
justify-content: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- transition: all 0.3s ease;
}
-.stat-card:hover {
- transform: translateY(-4px);
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
-}
.stat-number {
font-size: clamp(1.4rem, 3vw, 2.2rem);
@@ -258,7 +204,6 @@ body {
max-height: 392px;
min-height: 392px;
box-sizing: border-box;
- transition: all 0.3s ease;
-webkit-overflow-scrolling: touch;
}
@@ -319,9 +264,6 @@ body {
min-height: 20px;
}
-.virtualized-list::-webkit-scrollbar-thumb:hover {
- background: #a1a1a1;
-}
.virtualized-list {
scrollbar-width: thin;
@@ -333,7 +275,7 @@ body {
padding: 1px 4px;
}
-/* 密钥项 - 修复长密钥显示问题 */
+/* 原有的密钥项样式(向后兼容) */
.key-item {
display: flex;
justify-content: space-between;
@@ -344,17 +286,674 @@ body {
border: 1px solid var(--border-color);
gap: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
- transition: box-shadow 0.2s ease;
margin-bottom: 1px;
min-height: 60px;
width: 100%;
box-sizing: border-box;
}
-.key-item:hover {
+/* 新的横向布局密钥项 */
+.key-item-horizontal {
+ display: flex;
+ align-items: center;
+ padding: 16px 20px;
+ background: var(--bg-input);
+ /* 使用主题变量 */
+ border: 2px solid var(--border-color);
+ border-radius: 12px;
+ gap: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ margin-bottom: 1px;
+ height: 72px;
+ width: 100%;
+ box-sizing: border-box;
+ cursor: pointer;
+ transition: none;
+ /* 移除过渡效果 */
+}
+
+/* 左侧状态指示器 */
+.key-status-indicator {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 80px;
+ padding: 4px 8px;
+ border: 1px solid #28a745;
+ /* 默认绿色外线框 - 有效密钥 */
+ border-radius: 20px;
+ background: rgba(40, 167, 69, 0.1);
+ /* 默认淡绿色背景 - 有效密钥 */
+}
+
+/* 无效密钥的状态指示器 */
+.key-item-horizontal.status-invalid .key-status-indicator {
+ border: 1px solid #dc3545;
+ /* 红色外线框 */
+ background: rgba(220, 53, 69, 0.1);
+ /* 淡红色背景 */
+}
+
+/* 速率限制的状态指示器 */
+.key-item-horizontal.status-rate-limited .key-status-indicator {
+ border: 1px solid #ffc107;
+ /* 黄色外线框 */
+ background: rgba(255, 193, 7, 0.1);
+ /* 淡黄色背景 */
+}
+
+/* 付费密钥的状态指示器 */
+.key-item-horizontal.status-paid .key-status-indicator {
+ border: 1px solid #0d6efd;
+ /* 蓝色外线框 */
+ background: rgba(13, 110, 253, 0.1);
+ /* 淡蓝色背景 */
+}
+
+/* 测试中的状态指示器 */
+.key-item-horizontal.status-testing .key-status-indicator {
+ border: 1px solid #6c757d;
+ /* 灰色外线框 */
+ background: rgba(108, 117, 125, 0.1);
+ /* 淡灰色背景 */
+}
+
+/* 重试中的状态指示器 */
+.key-item-horizontal.status-retrying .key-status-indicator {
+ border: 1px solid #6c757d;
+ /* 灰色外线框 */
+ background: rgba(108, 117, 125, 0.1);
+ /* 淡灰色背景 */
+}
+
+
+.key-status-text {
+ color: white;
+ /* 深色主题:白色文字 */
+ font-size: 12px;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
+/* 浅色主题下的状态文字 */
+.key-item-horizontal.status-valid .key-status-text {
+ color: #343a40;
+ /* 浅色主题:深灰色文字 */
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-status-text {
+ color: white;
+ /* 深色主题:白色文字 */
+}
+
+/* 中间密钥显示区域 */
+.key-display-container {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ /* 允许选择内部文本 */
+ user-select: text;
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+}
+
+/* === 模仿 Semi Design Input 组件样式 === */
+
+/* Input 外层容器 */
+.semi-input-wrapper {
+ display: inline-flex;
+ align-items: center;
+ position: relative;
+ flex: 1;
+ min-width: 0;
+ background-color: var(--bg-input);
+ border: 1px solid var(--border-color);
+ border-radius: 10px;
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ /* 允许选择内部文本 */
+ user-select: text;
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+}
+
+.semi-input-wrapper:hover {
+ border-color: var(--primary-color);
+ background-color: var(--bg-input);
+}
+
+.semi-input-wrapper:focus-within {
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 2px var(--primary-color-alpha);
+ background-color: var(--bg-input);
+}
+
+/* 小尺寸变体 */
+.semi-input-wrapper-small {
+ height: 32px;
+ padding: 0 12px;
+ gap: 8px;
+}
+
+/* 可滚动的密钥显示容器 - 替代 input 元素 */
+.semi-input-scrollable {
+ flex: 1;
+ min-width: 0;
+ overflow-x: auto;
+ overflow-y: hidden;
+ display: flex;
+ align-items: center;
+ /* 隐藏滚动条但保留滚动功能 */
+ scrollbar-width: none;
+ /* Firefox */
+ -ms-overflow-style: none;
+ /* IE 和 Edge */
+}
+
+/* 隐藏 Webkit 浏览器的滚动条 */
+.semi-input-scrollable::-webkit-scrollbar {
+ display: none;
+}
+
+/* 密钥文本 */
+.semi-input-text {
+ font-family: 'Courier New', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace;
+ font-size: 13px;
+ letter-spacing: 0.5px;
+ font-weight: 500;
+ color: var(--text-primary);
+ white-space: nowrap;
+ line-height: 20px;
+ user-select: text;
+ -webkit-user-select: text;
+ cursor: text;
+}
+
+/* Suffix 区域 */
+.semi-input-suffix {
+ display: flex;
+ align-items: center;
+ gap: 0;
+ flex-shrink: 0;
+ margin-left: 4px;
+}
+
+/* === 模仿 Semi Design Button 组件样式 === */
+
+.semi-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid transparent;
+ border-radius: 8px;
+ font-size: 14px;
+ font-weight: 600;
+ line-height: 20px;
+ cursor: pointer;
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ user-select: none;
+ white-space: nowrap;
+ padding: 0;
+ background: transparent;
+}
+
+/* 小尺寸按钮 */
+.semi-button-small {
+ height: 28px;
+ width: 28px;
+ padding: 0;
+ font-size: 14px;
+}
+
+/* Borderless 无边框按钮 */
+.semi-button-borderless {
+ border: none;
+ background: transparent;
+}
+
+/* Tertiary 三级按钮 */
+.semi-button-tertiary {
+ color: var(--text-secondary);
+}
+
+.semi-button-tertiary:hover {
+ background-color: var(--bg-secondary);
+ color: var(--primary-color);
+}
+
+.semi-button-tertiary:active {
+ transform: scale(0.95);
+ background-color: var(--bg-secondary);
+}
+
+.semi-button-borderless.semi-button-tertiary:hover {
+ background-color: var(--bg-secondary);
+ color: var(--primary-color);
+}
+
+/* 按钮图标 */
+.semi-button svg {
+ display: block;
+}
+
+/* 状态信息行 */
+.key-info-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ font-size: 11px;
+ color: var(--text-secondary);
+ padding-left: 4px;
+}
+
+/* 可点击的状态信息行 */
+.key-info-clickable {
+ border: none;
+ background: none;
+ cursor: pointer;
+ padding: 4px;
+ margin-left: -4px;
+ border-radius: 6px;
+ transition: background-color 0.2s ease;
+ text-align: left;
+ width: 100%;
+}
+
+.key-info-clickable:hover {
+ background-color: var(--bg-secondary);
+}
+
+.key-status-info {
+ font-size: 11px;
+ color: var(--text-secondary);
+}
+
+/* 保留原有的中间密钥显示区域样式(向后兼容) */
+.key-display-legacy {
+ flex: 1;
+ min-width: 0;
+ /* 重置button默认样式 */
+ border: none;
+ background: none;
+ padding: 0;
+ text-align: left;
+ font: inherit;
+ color: inherit;
+ cursor: pointer;
+ display: block;
+ width: 100%;
+}
+
+.key-display-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 4px;
+}
+
+.key-capsule {
+ background: rgba(33, 37, 41, 0.9);
+ /* 深色主题:深灰色胶囊 */
+ padding: 8px 16px;
+ border-radius: 20px;
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+ width: 200px;
+ /* 固定宽度 */
+ overflow-x: auto;
+ /* 水平滚动 */
+ overflow-y: hidden;
+ position: relative;
+ /* 为渐变遮罩提供定位上下文 */
+}
+
+/* 浅色主题下的胶囊样式 */
+.key-item-horizontal.status-valid .key-capsule {
+ background: rgba(108, 117, 125, 0.2);
+ /* 浅色主题:更深的灰色胶囊 */
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-capsule {
+ background: rgba(33, 37, 41, 0.9);
+ /* 深色主题:深灰色胶囊 */
}
+/* 细滚动条样式 - 完全隐藏 */
+.key-capsule::-webkit-scrollbar {
+ display: none;
+}
+
+.key-capsule {
+ -ms-overflow-style: none;
+ /* IE 和 Edge */
+ scrollbar-width: none;
+ /* Firefox */
+}
+
+/* 右边缘渐变淡出效果 - 指示更多内容 */
+.key-capsule::after {
+ content: '';
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ width: 24px;
+ background: linear-gradient(to right, transparent, rgba(33, 37, 41, 0.9));
+ pointer-events: none;
+ /* 不阻挡指针事件 */
+ border-radius: 0 20px 20px 0;
+ /* 匹配胶囊右侧圆角 */
+}
+
+/* 浅色主题下的渐变遮罩 */
+.key-item-horizontal.status-valid .key-capsule::after {
+ background: linear-gradient(to right, transparent, rgba(108, 117, 125, 0.2));
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-capsule::after {
+ background: linear-gradient(to right, transparent, rgba(33, 37, 41, 0.9));
+}
+
+.key-text-masked {
+ font-family: 'Courier New', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Lucida Console', monospace;
+ font-size: 13px;
+ color: white;
+ /* 深色主题:白色文字 */
+ letter-spacing: 0.5px;
+ font-weight: 500;
+ white-space: nowrap;
+ /* 防止换行,让内容可滚动 */
+ min-width: fit-content;
+ /* 确保完整内容可见 */
+}
+
+/* 浅色主题下的密钥文字 */
+.key-item-horizontal.status-valid .key-text-masked {
+ color: #343a40;
+ /* 浅色主题:深灰色文字 */
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-text-masked {
+ color: white;
+ /* 深色主题:白色文字 */
+}
+
+.key-status-info-external {
+ font-size: 11px;
+ color: rgba(255, 255, 255, 0.7);
+ /* 深色主题:半透明白色 */
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+/* 浅色主题下的状态信息 */
+.key-item-horizontal.status-valid .key-status-info-external {
+ color: rgba(52, 58, 64, 0.7);
+ /* 浅色主题:半透明深灰色 */
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-status-info-external {
+ color: rgba(255, 255, 255, 0.7);
+ /* 深色主题:半透明白色 */
+}
+
+.key-error-info {
+ font-size: 11px;
+ color: #ffcccb;
+ margin-top: 2px;
+ line-height: 1.3;
+}
+
+/* 右侧操作按钮 */
+.key-actions {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+}
+
+.key-action-btn {
+ width: 36px;
+ height: 36px;
+ border: none;
+ background: rgba(255, 255, 255, 0.1);
+ /* 深色主题:半透明白色背景 */
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ color: rgba(255, 255, 255, 0.6);
+ /* 深色主题:半透明白色图标 */
+}
+
+/* 浅色主题下的操作按钮 */
+.key-item-horizontal.status-valid .key-action-btn {
+ background: rgba(52, 58, 64, 0.1);
+ /* 浅色主题:半透明深灰色背景 */
+ color: rgba(52, 58, 64, 0.6);
+ /* 浅色主题:半透明深灰色图标 */
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-action-btn {
+ background: rgba(255, 255, 255, 0.1);
+ /* 深色主题:半透明白色背景 */
+ color: rgba(255, 255, 255, 0.6);
+ /* 深色主题:半透明白色图标 */
+}
+
+.key-action-btn:hover {
+ background: rgba(255, 255, 255, 0.2);
+ /* 深色主题:悬停效果 */
+ color: rgba(255, 255, 255, 0.9);
+ transform: scale(1.05);
+}
+
+/* 浅色主题下的操作按钮悬停效果 */
+.key-item-horizontal.status-valid .key-action-btn:hover {
+ background: rgba(52, 58, 64, 0.2);
+ /* 浅色主题:悬停背景 */
+ color: rgba(52, 58, 64, 0.9);
+ /* 浅色主题:悬停图标 */
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-action-btn:hover {
+ background: rgba(255, 255, 255, 0.2);
+ /* 深色主题:悬停背景 */
+ color: rgba(255, 255, 255, 0.9);
+ /* 深色主题:悬停图标 */
+}
+
+/* 状态变体的 CSS 自定义属性定义 */
+.key-item-horizontal.status-valid,
+.key-item-horizontal.status-invalid,
+.key-item-horizontal.status-rate-limited,
+.key-item-horizontal.status-paid,
+.key-item-horizontal.status-testing,
+.key-item-horizontal.status-retrying {
+ --status-bg-light: #ffffff;
+ --status-bg-dark: #2c2c2c;
+ --status-border-light: #e0e0e0;
+ --status-border-dark: #404040;
+ --status-capsule-light: rgba(108, 117, 125, 0.2);
+ --status-capsule-dark: rgba(33, 37, 41, 0.9);
+ --status-text-light: #343a40;
+ --status-text-dark: white;
+ --status-info-light: rgba(52, 58, 64, 0.7);
+ --status-info-dark: rgba(255, 255, 255, 0.7);
+ --status-action-bg-light: rgba(52, 58, 64, 0.1);
+ --status-action-bg-dark: rgba(255, 255, 255, 0.1);
+ --status-action-color-light: rgba(52, 58, 64, 0.6);
+ --status-action-color-dark: rgba(255, 255, 255, 0.6);
+ --status-action-hover-bg-light: rgba(52, 58, 64, 0.2);
+ --status-action-hover-bg-dark: rgba(255, 255, 255, 0.2);
+ --status-action-hover-color-light: rgba(52, 58, 64, 0.9);
+ --status-action-hover-color-dark: rgba(255, 255, 255, 0.9);
+}
+
+/* 应用状态颜色的统一规则 */
+.key-item-horizontal.status-valid,
+.key-item-horizontal.status-invalid,
+.key-item-horizontal.status-rate-limited,
+.key-item-horizontal.status-paid,
+.key-item-horizontal.status-testing,
+.key-item-horizontal.status-retrying {
+ background: var(--status-bg-light);
+ border: 2px solid var(--status-border-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid,
+.dark-theme .key-item-horizontal.status-invalid,
+.dark-theme .key-item-horizontal.status-rate-limited,
+.dark-theme .key-item-horizontal.status-paid,
+.dark-theme .key-item-horizontal.status-testing,
+.dark-theme .key-item-horizontal.status-retrying {
+ background: var(--status-bg-dark);
+ border: 2px solid var(--status-border-dark);
+}
+
+/* 胶囊样式 */
+.key-item-horizontal.status-valid .key-capsule,
+.key-item-horizontal.status-invalid .key-capsule,
+.key-item-horizontal.status-rate-limited .key-capsule,
+.key-item-horizontal.status-paid .key-capsule,
+.key-item-horizontal.status-testing .key-capsule,
+.key-item-horizontal.status-retrying .key-capsule {
+ background: var(--status-capsule-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-capsule,
+.dark-theme .key-item-horizontal.status-invalid .key-capsule,
+.dark-theme .key-item-horizontal.status-rate-limited .key-capsule,
+.dark-theme .key-item-horizontal.status-paid .key-capsule,
+.dark-theme .key-item-horizontal.status-testing .key-capsule,
+.dark-theme .key-item-horizontal.status-retrying .key-capsule {
+ background: var(--status-capsule-dark);
+}
+
+/* 渐变遮罩 */
+.key-item-horizontal.status-valid .key-capsule::after,
+.key-item-horizontal.status-invalid .key-capsule::after,
+.key-item-horizontal.status-rate-limited .key-capsule::after,
+.key-item-horizontal.status-paid .key-capsule::after,
+.key-item-horizontal.status-testing .key-capsule::after,
+.key-item-horizontal.status-retrying .key-capsule::after {
+ background: linear-gradient(to right, transparent, var(--status-capsule-light));
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-capsule::after,
+.dark-theme .key-item-horizontal.status-invalid .key-capsule::after,
+.dark-theme .key-item-horizontal.status-rate-limited .key-capsule::after,
+.dark-theme .key-item-horizontal.status-paid .key-capsule::after,
+.dark-theme .key-item-horizontal.status-testing .key-capsule::after,
+.dark-theme .key-item-horizontal.status-retrying .key-capsule::after {
+ background: linear-gradient(to right, transparent, var(--status-capsule-dark));
+}
+
+/* 密钥文字颜色 */
+.key-item-horizontal.status-valid .key-text-masked,
+.key-item-horizontal.status-invalid .key-text-masked,
+.key-item-horizontal.status-rate-limited .key-text-masked,
+.key-item-horizontal.status-paid .key-text-masked,
+.key-item-horizontal.status-testing .key-text-masked,
+.key-item-horizontal.status-retrying .key-text-masked {
+ color: var(--status-text-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-text-masked,
+.dark-theme .key-item-horizontal.status-invalid .key-text-masked,
+.dark-theme .key-item-horizontal.status-rate-limited .key-text-masked,
+.dark-theme .key-item-horizontal.status-paid .key-text-masked,
+.dark-theme .key-item-horizontal.status-testing .key-text-masked,
+.dark-theme .key-item-horizontal.status-retrying .key-text-masked {
+ color: var(--status-text-dark);
+}
+
+/* 状态文字颜色 */
+.key-item-horizontal.status-valid .key-status-text,
+.key-item-horizontal.status-invalid .key-status-text,
+.key-item-horizontal.status-rate-limited .key-status-text,
+.key-item-horizontal.status-paid .key-status-text,
+.key-item-horizontal.status-testing .key-status-text,
+.key-item-horizontal.status-retrying .key-status-text {
+ color: var(--status-text-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-status-text,
+.dark-theme .key-item-horizontal.status-invalid .key-status-text,
+.dark-theme .key-item-horizontal.status-rate-limited .key-status-text,
+.dark-theme .key-item-horizontal.status-paid .key-status-text,
+.dark-theme .key-item-horizontal.status-testing .key-status-text,
+.dark-theme .key-item-horizontal.status-retrying .key-status-text {
+ color: var(--status-text-dark);
+}
+
+/* 状态信息外部颜色 */
+.key-item-horizontal.status-valid .key-status-info-external,
+.key-item-horizontal.status-invalid .key-status-info-external,
+.key-item-horizontal.status-rate-limited .key-status-info-external,
+.key-item-horizontal.status-paid .key-status-info-external,
+.key-item-horizontal.status-testing .key-status-info-external,
+.key-item-horizontal.status-retrying .key-status-info-external {
+ color: var(--status-info-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-status-info-external,
+.dark-theme .key-item-horizontal.status-invalid .key-status-info-external,
+.dark-theme .key-item-horizontal.status-rate-limited .key-status-info-external,
+.dark-theme .key-item-horizontal.status-paid .key-status-info-external,
+.dark-theme .key-item-horizontal.status-testing .key-status-info-external,
+.dark-theme .key-item-horizontal.status-retrying .key-status-info-external {
+ color: var(--status-info-dark);
+}
+
+/* 操作按钮样式 */
+.key-item-horizontal.status-valid .key-action-btn,
+.key-item-horizontal.status-invalid .key-action-btn,
+.key-item-horizontal.status-rate-limited .key-action-btn,
+.key-item-horizontal.status-paid .key-action-btn,
+.key-item-horizontal.status-testing .key-action-btn,
+.key-item-horizontal.status-retrying .key-action-btn {
+ background: var(--status-action-bg-light);
+ color: var(--status-action-color-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-action-btn,
+.dark-theme .key-item-horizontal.status-invalid .key-action-btn,
+.dark-theme .key-item-horizontal.status-rate-limited .key-action-btn,
+.dark-theme .key-item-horizontal.status-paid .key-action-btn,
+.dark-theme .key-item-horizontal.status-testing .key-action-btn,
+.dark-theme .key-item-horizontal.status-retrying .key-action-btn {
+ background: var(--status-action-bg-dark);
+ color: var(--status-action-color-dark);
+}
+
+/* 操作按钮悬停效果 */
+.key-item-horizontal.status-valid .key-action-btn:hover,
+.key-item-horizontal.status-invalid .key-action-btn:hover,
+.key-item-horizontal.status-rate-limited .key-action-btn:hover,
+.key-item-horizontal.status-paid .key-action-btn:hover,
+.key-item-horizontal.status-testing .key-action-btn:hover,
+.key-item-horizontal.status-retrying .key-action-btn:hover {
+ background: var(--status-action-hover-bg-light);
+ color: var(--status-action-hover-color-light);
+}
+
+.dark-theme .key-item-horizontal.status-valid .key-action-btn:hover,
+.dark-theme .key-item-horizontal.status-invalid .key-action-btn:hover,
+.dark-theme .key-item-horizontal.status-rate-limited .key-action-btn:hover,
+.dark-theme .key-item-horizontal.status-paid .key-action-btn:hover,
+.dark-theme .key-item-horizontal.status-testing .key-action-btn:hover,
+.dark-theme .key-item-horizontal.status-retrying .key-action-btn:hover {
+ background: var(--status-action-hover-bg-dark);
+ color: var(--status-action-hover-color-dark);
+}
+
+
/* 密钥内容 */
.key-content {
flex: 1;
@@ -527,6 +1126,7 @@ body {
flex-shrink: 0;
width: 100%;
padding: var(--spacing-xs) 0;
+ margin-top: -8px;
}
.copy-btn {
@@ -538,7 +1138,6 @@ body {
cursor: pointer;
font-size: var(--font-size-base);
font-weight: 600;
- transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
@@ -549,37 +1148,18 @@ body {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
-.copy-btn:hover {
- background: var(--color-primary);
- opacity: 0.9;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
-}
/* 深色主题 */
.dark-theme .function-card {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
-.dark-theme .function-card:hover {
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
-}
-.dark-theme .settings-button {
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
-}
-
-.dark-theme .settings-button:hover {
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
-}
.dark-theme .stat-card {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
-.dark-theme .stat-card:hover {
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
-}
.dark-theme .results-card {
background: #2a2a2a;
@@ -594,17 +1174,11 @@ body {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
-.dark-theme .key-item:hover {
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
-}
.dark-theme .copy-btn {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
-.dark-theme .copy-btn:hover {
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
-}
.dark-theme .key-status.status-valid {
background: #155724;
@@ -627,9 +1201,6 @@ body {
color: var(--text-primary);
}
-.dark-theme .settings-button {
- background: var(--color-secondary);
-}
/* 深色主题的滚动条 */
.dark-theme .virtualized-list::-webkit-scrollbar-track {
@@ -640,9 +1211,6 @@ body {
background: #666;
}
-.dark-theme .virtualized-list::-webkit-scrollbar-thumb:hover {
- background: #888;
-}
.dark-theme .virtualized-list {
scrollbar-color: #666 #333;
@@ -669,9 +1237,6 @@ body {
border-radius: 3px;
}
-*::-webkit-scrollbar-thumb:hover {
- background: #a1a1a1;
-}
/* 深色主题全局滚动条 */
.dark-theme * {
@@ -686,9 +1251,6 @@ body {
background: #666;
}
-.dark-theme *::-webkit-scrollbar-thumb:hover {
- background: #888;
-}
/* 工具类 */
.hidden {
@@ -714,20 +1276,11 @@ body {
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);
}
- .function-card:hover {
- box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12);
- transform: translateY(-1px);
- }
.usage-card {
padding: var(--spacing-xs) var(--spacing-sm);
}
- .settings-button {
- min-height: 40px;
- font-size: 14px;
- padding: var(--spacing-sm) var(--spacing-md);
- }
.results-card {
max-height: 400px;
@@ -743,6 +1296,79 @@ body {
max-height: 300px;
}
+ /* 移动端横向密钥卡片优化 */
+ .key-item-horizontal {
+ padding: 12px 16px;
+ gap: 12px;
+ height: 64px;
+ min-height: 64px;
+ }
+
+ /* 状态指示器在移动端缩小 */
+ .key-status-indicator {
+ min-width: 60px;
+ padding: 3px 6px;
+ }
+
+ .key-status-text {
+ font-size: 10px;
+ }
+
+ /* 新版密钥输入框在移动端优化 */
+ .semi-input-wrapper {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .semi-input-wrapper-small {
+ height: 30px;
+ padding: 0 10px;
+ }
+
+ .semi-input-text {
+ font-size: 12px;
+ }
+
+ .semi-button-small {
+ height: 26px;
+ width: 26px;
+ }
+
+ .key-info-row {
+ font-size: 10px;
+ gap: 8px;
+ }
+
+ /* 旧版密钥胶囊在移动端自适应宽度(向后兼容) */
+ .key-capsule {
+ width: auto;
+ min-width: 120px;
+ max-width: 160px;
+ flex: 1;
+ padding: 6px 12px;
+ }
+
+ .key-text-masked {
+ font-size: 12px;
+ }
+
+ .key-status-info-external {
+ font-size: 10px;
+ display: none;
+ /* 在移动端隐藏状态码信息以节省空间 */
+ }
+
+ /* 操作按钮在移动端加大触摸区域 */
+ .key-actions {
+ gap: 6px;
+ }
+
+ .key-action-btn {
+ width: 40px;
+ height: 40px;
+ }
+
+ /* 旧版密钥项样式保持向后兼容 */
.key-item {
flex-direction: column;
align-items: flex-start;
@@ -798,7 +1424,7 @@ body {
}
.empty-state {
- min-height: 300px;
+ min-height: 120px;
padding: var(--spacing-md);
}
@@ -824,6 +1450,72 @@ body {
max-height: 250px;
}
+ /* 超小屏幕下进一步优化密钥卡片 */
+ .key-item-horizontal {
+ padding: 10px 12px;
+ gap: 10px;
+ height: 60px;
+ min-height: 60px;
+ }
+
+ /* 状态指示器进一步缩小 */
+ .key-status-indicator {
+ min-width: 50px;
+ padding: 2px 4px;
+ }
+
+ .key-status-text {
+ font-size: 9px;
+ }
+
+ /* 新版密钥输入框在超小屏幕下优化 */
+ .semi-input-wrapper {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .semi-input-wrapper-small {
+ height: 28px;
+ padding: 0 8px;
+ }
+
+ .semi-input,
+ .semi-input-small {
+ font-size: 11px;
+ }
+
+ .semi-button-small {
+ height: 24px;
+ width: 24px;
+ }
+
+ .semi-button-small svg {
+ width: 14px;
+ height: 14px;
+ }
+
+ .key-info-row {
+ font-size: 9px;
+ gap: 6px;
+ }
+
+ /* 旧版密钥胶囊在超小屏幕下更紧凑(向后兼容) */
+ .key-capsule {
+ min-width: 100px;
+ max-width: 130px;
+ padding: 5px 10px;
+ }
+
+ .key-text-masked {
+ font-size: 11px;
+ }
+
+ /* 操作按钮保持合适的触摸区域但稍小一些 */
+ .key-action-btn {
+ width: 36px;
+ height: 36px;
+ }
+
.stat-card {
min-height: 60px;
min-width: 50px;
@@ -881,18 +1573,11 @@ body {
background: white;
border-radius: 6px;
cursor: pointer;
- transition: all 0.2s ease;
font-size: 14px;
color: #495057;
}
/* 浅色主题悬浮效果 */
-.controlBtn:hover:not(:disabled) {
- background: #f8f9fa;
- border-color: #adb5bd;
- transform: translateY(-1px);
- color: #343a40;
-}
.controlBtn:disabled {
opacity: 0.6;
@@ -906,11 +1591,6 @@ body {
color: #495057;
}
-.importBtn:hover:not(:disabled) {
- background: #f8f9fa;
- border-color: #adb5bd;
- color: #343a40;
-}
/* 粘贴按钮特殊样式 */
.pasteBtn {
@@ -927,11 +1607,6 @@ body {
color: #495057;
}
-.pasteBtn:hover:not(:disabled) {
- background: #f8f9fa;
- border-color: #adb5bd;
- color: #343a40;
-}
/* 深色主题下的控制按钮 */
:global(.dark-theme) .controlBtn {
@@ -940,11 +1615,6 @@ body {
color: #e8eaed;
}
-:global(.dark-theme) .controlBtn:hover:not(:disabled) {
- background: #3a3a3a;
- border-color: #555555;
- color: #ffffff;
-}
:global(.dark-theme) .importBtn {
background: #2a2a2a;
@@ -952,11 +1622,6 @@ body {
color: #e8eaed;
}
-:global(.dark-theme) .importBtn:hover:not(:disabled) {
- background: #3a3a3a;
- border-color: #555555;
- color: #ffffff;
-}
:global(.dark-theme) .pasteBtn {
background: #1a1a1a;
@@ -964,11 +1629,6 @@ body {
color: #e8eaed;
}
-:global(.dark-theme) .pasteBtn:hover:not(:disabled) {
- background: #2a2a2a;
- border-color: #444444;
- color: #ffffff;
-}
/* Results tooltip */
.results-tooltip {
@@ -1002,10 +1662,6 @@ body {
line-height: 1;
}
-.results-tooltip__close:hover,
-.results-tooltip__close:focus {
- color: var(--color-info);
-}
.dark-theme .results-tooltip {
background: rgba(23, 162, 184, 0.12);
@@ -1013,10 +1669,6 @@ body {
color: var(--text-primary);
}
-.dark-theme .results-tooltip__close:hover,
-.dark-theme .results-tooltip__close:focus {
- color: #93c5fd;
-}
.log-modal-content {
width: 100%;