<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TENG YUAN界面 - 集成终端系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
/* ==================== CSS变量定义 ==================== */
:root {
--nav-width: 5.5rem;
--nav-height: 5.5rem;
/* 终端相关变量 */
--editor-bg: #1e1e1e;
--editor-secondary-bg: #252526;
--line-color: #858585;
--text-color: #d4d4d4;
--keyword-color: #569cd6;
--string-color: #ce9178;
--comment-color: #6a9955;
--number-color: #b5cea8;
--function-color: #dcdcaa;
--font-family: 'JetBrains Mono', 'Consolas', 'Monaco', monospace;
--header-bg: #2d2d2d;
--window-btn-close: #ff5f56;
--window-btn-minimize: #ffbd2e;
--window-btn-max: #27c93f;
--ai-output-color: #4ec9b0;
--user-input-color: #d7ba7d;
--accent-color: #0a84ff;
--accent-hover: #409eff;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
--border-radius: 8px;
--transition-fast: 0.2s ease;
--transition-normal: 0.3s ease;
--transition-slow: 0.5s ease;
/* 起始页变量 */
--startup-bg: #0a0a0a;
--startup-overlay: radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.08) 0%, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(120, 219, 255, 0.06) 0%, transparent 50%);
--startup-card-bg: rgba(255, 255, 255, 0.04);
--startup-card-hover: rgba(255, 255, 255, 0.08);
--startup-card-border: rgba(255, 255, 255, 0.08);
--startup-text: #ffffff;
--startup-text-secondary: rgba(255, 255, 255, 0.65);
--startup-text-tertiary: rgba(255, 255, 255, 0.45);
--startup-accent: #5b9bd5;
--startup-accent-hover: #7bb3e8;
/* 主页Tab样式变量 */
--tab-bg: rgba(255, 255, 255, 0.95);
--tab-border: rgba(0, 0, 0, 0.08);
--tab-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
--tab-active-bg: #6366f1;
--tab-text: #374151;
--tab-text-active: #ffffff;
--card-bg: rgba(255, 255, 255, 0.9);
--card-border: rgba(0, 0, 0, 0.06);
--card-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
--search-bg: rgba(255, 255, 255, 0.95);
--search-border: rgba(0, 0, 0, 0.1);
/* 主题编辑器变量 */
--primary-hue: 243;
--primary-saturation: 75%;
--primary-lightness: 59%;
--background-opacity: 0.85;
--blur-strength: 12px;
--border-radius-size: 1.5rem;
}
[data-theme="light"] {
--editor-bg: #f5f5f5;
--editor-secondary-bg: #ebebeb;
--line-color: #858585;
--text-color: #333333;
--keyword-color: #0000ff;
--string-color: #a31515;
--comment-color: #008000;
--number-color: #098658;
--function-color: #795e26;
--header-bg: #e5e5e5;
--ai-output-color: #098658;
--user-input-color: #0000ff;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
--startup-bg: #fafbfc;
--startup-overlay: radial-gradient(circle at 20% 50%, rgba(91, 155, 213, 0.08) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.06) 0%, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(120, 219, 255, 0.05) 0%, transparent 50%);
--startup-card-bg: rgba(255, 255, 255, 0.8);
--startup-card-hover: rgba(255, 255, 255, 0.95);
--startup-card-border: rgba(0, 0, 0, 0.06);
--startup-text: #1a1a1a;
--startup-text-secondary: rgba(26, 26, 26, 0.7);
--startup-text-tertiary: rgba(26, 26, 26, 0.5);
--startup-accent: #0066cc;
--startup-accent-hover: #0052a3;
}
body.dark-mode {
--tab-bg: rgba(30, 41, 59, 0.95);
--tab-border: rgba(255, 255, 255, 0.1);
--tab-shadow: 0 2px 20px rgba(0, 0, 0, 0.3);
--tab-active-bg: #8b5cf6;
--tab-text: #e2e8f0;
--tab-text-active: #ffffff;
--card-bg: rgba(30, 41, 59, 0.9);
--card-border: rgba(255, 255, 255, 0.1);
--card-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
--search-bg: rgba(30, 41, 59, 0.95);
--search-border: rgba(255, 255, 255, 0.2);
}
/* 动态主题色彩 */
.theme-primary {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
}
.theme-primary-hover {
background: hsl(var(--primary-hue), var(--primary-saturation), calc(var(--primary-lightness) + 10%));
}
.theme-primary-text {
color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
overflow: hidden;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
height: 100vh;
transition: all 0.3s ease;
}
/* 白天模式 */
body.light-mode {
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
color: #1f2937;
}
/* 夜间模式 */
body.dark-mode {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
color: #f8fafc;
}
/* 应用容器 */
#app {
height: 100vh;
position: relative;
}
/* ==================== 内容区域样式 ==================== */
body.light-mode #content {
background: rgba(255, 255, 255, var(--background-opacity));
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow:
0 10px 25px -5px rgba(0, 0, 0, 0.05),
0 8px 10px -6px rgba(0, 0, 0, 0.02),
inset 0 -1px 0 rgba(0, 0, 0, 0.05),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
body.dark-mode #content {
background: rgba(15, 23, 42, var(--background-opacity));
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 20px 25px -5px rgba(0, 0, 0, 0.2),
0 10px 10px -5px rgba(0, 0, 0, 0.1),
inset 0 -1px 0 rgba(255, 255, 255, 0.05),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
#content {
position: absolute;
top: 1rem;
left: 1rem;
right: 1rem;
bottom: 1rem;
backdrop-filter: blur(var(--blur-strength));
-webkit-backdrop-filter: blur(var(--blur-strength));
border-radius: var(--border-radius-size);
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 1;
display: flex;
flex-direction: column;
overflow: hidden;
will-change: transform;
}
/* ==================== 导航栏样式 ==================== */
.top-nav {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: var(--nav-height);
display: flex;
gap: 0.75rem;
padding: 0.75rem;
transform: translateY(-100%);
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: auto;
border: none;
}
.side-nav {
position: absolute;
top: 0;
left: 0;
width: var(--nav-width);
height: 100%;
padding-top: var(--nav-height);
display: flex;
flex-direction: column;
gap: 0.75rem;
padding: 0.75rem;
transform: translateX(-100%);
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: auto;
will-change: transform;
border: none;
}
body.light-mode .top-nav,
body.light-mode .side-nav {
background: rgba(249, 250, 251, 0.95);
box-shadow:
0 5px 15px -5px rgba(0, 0, 0, 0.05),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
body.dark-mode .top-nav,
body.dark-mode .side-nav {
background: rgba(15, 23, 42, 0.95);
box-shadow:
0 10px 15px -5px rgba(0, 0, 0, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
/* ==================== 头部样式 ==================== */
body.light-mode header {
background: rgba(255, 255, 255, 0.7);
border-bottom: 1px solid rgba(229, 231, 235, 0.5);
box-shadow:
0 2px 4px -1px rgba(0, 0, 0, 0.02),
0 1px 2px -1px rgba(0, 0, 0, 0.01);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
body.dark-mode header {
background: rgba(15, 23, 42, 0.7);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
header {
height: 5.5rem;
display: flex;
align-items: center;
padding: 0 2rem;
border-top-left-radius: var(--border-radius-size);
border-top-right-radius: var(--border-radius-size);
}
/* ==================== 天气显示样式 ==================== */
body.light-mode .weather-widget {
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(229, 231, 235, 0.5);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
body.dark-mode .weather-widget {
background: rgba(30, 41, 59, 0.7);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.weather-widget {
margin-left: auto;
display: flex;
align-items: center;
gap: 1rem;
border-radius: 1rem;
padding: 0.5rem 1.25rem;
transition: all 0.3s ease;
position: relative;
cursor: pointer;
}
.weather-widget:hover {
transform: translateY(-2px);
}
body.light-mode .weather-widget:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
body.dark-mode .weather-widget:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
}
.weather-icon {
font-size: 1.5rem;
transition: all 0.3s ease;
}
body.light-mode .weather-icon {
color: #4b5563;
}
body.dark-mode .weather-icon {
color: #f8fafc;
}
.weather-info {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.weather-temp {
font-weight: 600;
font-size: 1rem;
transition: all 0.3s ease;
white-space: nowrap;
}
body.light-mode .weather-temp {
color: #1f2937;
}
body.dark-mode .weather-temp {
color: #f8fafc;
}
.welcome-message {
font-size: 0.75rem;
display: flex;
align-items: center;
gap: 0.25rem;
transition: all 0.3s ease;
white-space: nowrap;
}
body.light-mode .welcome-message {
color: #6b7280;
}
body.dark-mode .welcome-message {
color: #94a3b8;
}
/* ==================== 主要内容区域 ==================== */
main {
flex: 1;
padding: 0;
overflow-y: auto;
background: transparent;
-webkit-overflow-scrolling: touch;
position: relative;
}
/* ==================== 导航按钮样式 ==================== */
.nav-toggle {
width: 3rem;
height: 3rem;
border: none;
border-radius: 0.75rem;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06),
0 0 0 2px rgba(255, 255, 255, 0.2);
position: relative;
overflow: hidden;
z-index: 1;
will-change: transform;
}
.nav-toggle::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: hsl(var(--primary-hue), var(--primary-saturation), calc(var(--primary-lightness) + 10%));
opacity: 0;
transition: opacity 0.3s ease;
z-index: -1;
}
.nav-toggle:hover {
transform: translateY(-2px) scale(1.05);
box-shadow:
0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05),
0 0 0 2px rgba(255, 255, 255, 0.3);
}
.nav-toggle:hover::before {
opacity: 1;
}
.nav-toggle:active {
transform: translateY(0) scale(0.98);
}
/* ==================== 导航项样式 ==================== */
body.light-mode .nav-item {
background: rgba(255, 255, 255, 0.8);
color: #4b5563;
box-shadow:
0 1px 3px 0 rgba(0, 0, 0, 0.05),
0 1px 2px 0 rgba(0, 0, 0, 0.03),
inset 0 -1px 0 rgba(0, 0, 0, 0.05),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
border: 1px solid rgba(255, 255, 255, 0.3);
}
body.dark-mode .nav-item {
background: rgba(30, 41, 59, 0.8);
color: #cbd5e1;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06),
inset 0 -1px 0 rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.nav-item {
display: block;
border-radius: 0.75rem;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
will-change: transform;
cursor: pointer;
text-decoration: none;
}
.side-nav .nav-item {
width: calc(var(--nav-width) - 1.5rem);
height: calc(var(--nav-width) - 1.5rem);
}
.top-nav .nav-item {
width: calc(var(--nav-height) - 1.5rem);
height: calc(var(--nav-height) - 1.5rem);
}
.nav-item::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg,
hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness)) 0%,
hsl(var(--primary-hue), calc(var(--primary-saturation) + 10%), calc(var(--primary-lightness) + 10%)) 100%);
opacity: 0;
transition: all 0.3s ease;
z-index: -1;
}
.nav-item:hover {
transform: translateY(-3px);
color: white;
}
body.light-mode .nav-item:hover {
box-shadow:
0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05),
0 0 0 1px rgba(255, 255, 255, 0.4);
border-color: rgba(255, 255, 255, 0.5);
}
body.dark-mode .nav-item:hover {
box-shadow:
0 10px 15px -3px rgba(0, 0, 0, 0.2),
0 4px 6px -2px rgba(0, 0, 0, 0.1),
0 0 0 1px rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.2);
}
.nav-item:hover::before {
opacity: 1;
}
.nav-item i {
transition: all 0.3s ease;
}
.nav-item:hover i {
transform: scale(1.15);
}
body.light-mode .nav-item:hover i {
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
}
body.dark-mode .nav-item:hover i {
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
.nav-item::after {
content: attr(title);
position: absolute;
left: 100%;
top: 50%;
transform: translateY(-50%);
margin-left: 1rem;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
font-size: 0.85rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: all 0.3s ease;
z-index: 10;
backdrop-filter: blur(10px);
}
body.light-mode .nav-item::after {
background: rgba(31, 41, 55, 0.9);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
body.dark-mode .nav-item::after {
background: rgba(15, 23, 42, 0.95);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
}
.nav-item:hover::after {
opacity: 1;
margin-left: 1.5rem;
}
/* ==================== 打开状态下的样式 ==================== */
#app.open #content {
top: calc(var(--nav-height) + 1rem);
left: calc(var(--nav-width) + 1rem);
right: 1rem;
bottom: 1rem;
border-top-left-radius: 0;
}
#app.open .side-nav {
transform: translateX(0);
}
#app.open .top-nav {
transform: translateY(0);
}
/* ==================== 页面标题 ==================== */
#page-title {
background: linear-gradient(135deg,
hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness)) 0%,
hsl(var(--primary-hue), calc(var(--primary-saturation) + 10%), calc(var(--primary-lightness) + 10%)) 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-weight: 700;
letter-spacing: -0.025em;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* ==================== 主界面内容 ==================== */
.main-content {
display: none;
animation: fadeIn 0.5s ease forwards;
height: 100%;
backface-visibility: hidden;
transform: translate3d(0, 0, 0);
}
#home {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ==================== 新主页Tab样式 ==================== */
.home-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow: hidden;
}
.home-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.2) 0%, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(120, 219, 255, 0.2) 0%, transparent 50%);
animation: backgroundShift 20s ease-in-out infinite;
}
@keyframes backgroundShift {
0%, 100% {
background-position: 0% 0%, 30% 40%, 70% 80%;
}
50% {
background-position: 100% 100%, 60% 20%, 40% 60%;
}
}
/* 搜索区域 */
.home-search-section {
padding: 2rem 1.5rem 1rem;
position: relative;
z-index: 2;
}
.home-search-container {
position: relative;
max-width: 600px;
margin: 0 auto;
display: flex;
align-items: center;
gap: 12px;
}
.search-engine-selector {
display: flex;
background: var(--search-bg);
border: 1px solid var(--search-border);
border-radius: 20px;
padding: 4px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--tab-shadow);
position: relative;
}
.search-engine-btn {
width: 40px;
height: 40px;
border: none;
background: transparent;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
color: var(--tab-text);
position: relative;
overflow: hidden;
}
.search-engine-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
opacity: 0;
transition: opacity 0.3s ease;
border-radius: 16px;
}
.search-engine-btn.active::before {
opacity: 1;
}
.search-engine-btn.active {
color: white;
box-shadow: 0 2px 8px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.3);
}
.search-engine-btn:hover:not(.active) {
background: hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.1);
}
.search-engine-btn i {
position: relative;
z-index: 1;
}
.search-input-wrapper {
position: relative;
flex: 1;
}
.home-search-input {
width: 100%;
height: 56px;
padding: 0 24px 0 56px;
font-size: 1rem;
border: 1px solid var(--search-border);
border-radius: 28px;
background: var(--search-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
color: var(--tab-text);
transition: all 0.3s ease;
font-family: inherit;
box-shadow: var(--tab-shadow);
}
.home-search-input:focus {
outline: none;
border-color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
box-shadow: 0 0 0 3px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.1), var(--tab-shadow);
transform: translateY(-2px);
}
.home-search-input::placeholder {
color: var(--startup-text-tertiary);
}
.home-search-icon {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
width: 20px;
height: 20px;
color: var(--startup-text-tertiary);
pointer-events: none;
}
/* Tab导航 */
.home-tabs {
padding: 0 1.5rem;
position: relative;
z-index: 2;
display: flex;
align-items: center;
gap: 16px;
}
.tab-nav {
display: flex;
background: var(--tab-bg);
border: 1px solid var(--tab-border);
border-radius: 16px;
padding: 6px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--tab-shadow);
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
flex: 1;
}
.tab-nav::-webkit-scrollbar {
display: none;
}
.tab-button {
flex: 1;
min-width: 80px;
padding: 12px 16px;
border: none;
background: transparent;
color: var(--tab-text);
font-size: 0.9rem;
font-weight: 500;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
white-space: nowrap;
position: relative;
overflow: hidden;
}
.tab-button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
opacity: 0;
transition: opacity 0.3s ease;
}
.tab-button.active::before {
opacity: 1;
}
.tab-button.active {
color: white;
box-shadow: 0 4px 12px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.3);
}
.tab-button:not(.active):hover {
background: hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.1);
transform: translateY(-1px);
}
.tab-button span {
position: relative;
z-index: 1;
}
.tab-actions {
display: flex;
gap: 8px;
}
.tab-action-btn {
width: 40px;
height: 40px;
border: 1px solid var(--tab-border);
background: var(--tab-bg);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
color: var(--tab-text);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--tab-shadow);
position: relative;
overflow: hidden;
}
.tab-action-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
opacity: 0;
transition: opacity 0.3s ease;
}
.tab-action-btn:hover::before {
opacity: 1;
}
.tab-action-btn:hover {
color: white;
transform: translateY(-2px);
box-shadow: 0 8px 25px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.3);
}
.tab-action-btn i {
position: relative;
z-index: 1;
}
/* Tab内容区域 */
.home-content {
flex: 1;
padding: 1.5rem;
position: relative;
z-index: 2;
overflow-y: auto;
}
.tab-content {
display: none;
animation: slideIn 0.3s ease forwards;
}
.tab-content.active {
display: block;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 网站卡片网格 */
.sites-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 16px;
max-width: 1200px;
margin: 0 auto;
}
.site-card {
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 16px;
padding: 20px 16px;
text-align: center;
text-decoration: none;
color: var(--tab-text);
transition: all 0.3s ease;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
position: relative;
overflow: hidden;
cursor: pointer;
}
.site-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.6s ease;
}
.site-card:hover::before {
left: 100%;
}
.site-card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
border-color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
}
.site-icon {
width: 48px;
height: 48px;
margin: 0 auto 12px;
background: linear-gradient(135deg,
hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness)),
hsl(var(--primary-hue), calc(var(--primary-saturation) + 10%), calc(var(--primary-lightness) + 10%)));
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: white;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.site-card:hover .site-icon {
transform: scale(1.1);
box-shadow: 0 8px 25px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.4);
}
.site-icon img {
width: 28px;
height: 28px;
object-fit: contain;
border-radius: 6px;
}
.site-name {
font-size: 0.9rem;
font-weight: 600;
margin-bottom: 4px;
line-height: 1.3;
}
.site-desc {
font-size: 0.75rem;
opacity: 0.7;
line-height: 1.3;
}
/* 特殊卡片样式 */
.feature-card {
grid-column: span 2;
background: linear-gradient(135deg,
hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness)),
hsl(var(--primary-hue), calc(var(--primary-saturation) + 10%), calc(var(--primary-lightness) + 10%)));
color: white;
border: none;
}
.feature-card .site-icon {
background: rgba(255, 255, 255, 0.2);
}
.feature-card .site-desc {
opacity: 0.9;
}
/* 快速操作区域 */
.quick-actions {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
margin-bottom: 24px;
}
.quick-action {
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 12px;
padding: 16px 12px;
text-align: center;
text-decoration: none;
color: var(--tab-text);
transition: all 0.3s ease;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
cursor: pointer;
}
.quick-action:hover {
transform: translateY(-4px);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
border-color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
}
.quick-action-icon {
width: 32px;
height: 32px;
margin: 0 auto 8px;
background: linear-gradient(135deg,
hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness)),
hsl(var(--primary-hue), calc(var(--primary-saturation) + 10%), calc(var(--primary-lightness) + 10%)));
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
color: white;
}
.quick-action-name {
font-size: 0.8rem;
font-weight: 500;
}
/* ==================== 主题编辑器样式 ==================== */
.theme-editor {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
max-width: 500px;
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 20px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
z-index: 3000;
display: none;
animation: modalSlideIn 0.3s ease;
}
.theme-editor.show {
display: block;
}
.theme-editor-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 2rem;
border-bottom: 1px solid var(--card-border);
}
.theme-editor-header h3 {
color: var(--tab-text);
font-size: 1.25rem;
font-weight: 600;
}
.theme-editor-close {
width: 32px;
height: 32px;
border: none;
background: transparent;
cursor: pointer;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: var(--startup-text-tertiary);
transition: all 0.3s ease;
}
.theme-editor-close:hover {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.theme-editor-body {
padding: 2rem;
}
.theme-control-group {
margin-bottom: 2rem;
}
.theme-control-group label {
display: block;
margin-bottom: 0.75rem;
color: var(--tab-text);
font-weight: 500;
font-size: 0.9rem;
}
.theme-slider {
width: 100%;
height: 6px;
border-radius: 3px;
background: var(--card-border);
outline: none;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
}
.theme-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
cursor: pointer;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
}
.theme-slider::-webkit-slider-thumb:hover {
transform: scale(1.2);
}
.theme-slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
cursor: pointer;
border: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}
.theme-preset-colors {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
margin-top: 1rem;
}
.theme-preset-color {
width: 40px;
height: 40px;
border-radius: 12px;
cursor: pointer;
border: 2px solid transparent;
transition: all 0.3s ease;
position: relative;
}
.theme-preset-color:hover {
transform: scale(1.1);
border-color: var(--tab-text);
}
.theme-preset-color.active {
border-color: var(--tab-text);
box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 4px var(--tab-text);
}
.theme-value-display {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 0.5rem;
font-size: 0.85rem;
color: var(--startup-text-tertiary);
}
.theme-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid var(--card-border);
}
.theme-btn {
padding: 10px 20px;
border-radius: 10px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
border: none;
font-size: 0.9rem;
}
.theme-btn-primary {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
box-shadow: 0 4px 12px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.3);
}
.theme-btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.4);
}
.theme-btn-secondary {
background: transparent;
color: var(--tab-text);
border: 1px solid var(--card-border);
}
.theme-btn-secondary:hover {
background: var(--card-bg);
transform: translateY(-2px);
}
/* ==================== 使用统计样式 ==================== */
.stats-container {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow-y: auto;
padding: 2rem;
}
.stats-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 2rem;
color: white;
}
.stats-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.stats-card {
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 20px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
}
.stats-card h3 {
color: var(--tab-text);
margin-bottom: 1.5rem;
font-size: 1.25rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 0.5rem;
}
.stats-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
margin-bottom: 0.75rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.stats-item-label {
color: var(--tab-text);
font-weight: 500;
}
.stats-item-value {
color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
font-weight: 600;
font-size: 1.1rem;
}
.stats-chart {
height: 200px;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
color: var(--startup-text-tertiary);
font-style: italic;
}
/* ==================== 响应式设计 ==================== */
@media (max-width: 768px) {
.home-search-container {
flex-direction: column;
gap: 8px;
}
.search-engine-selector {
order: 2;
align-self: stretch;
justify-content: center;
}
.search-input-wrapper {
order: 1;
}
.home-tabs {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.tab-actions {
justify-content: center;
}
.theme-editor {
width: 95%;
margin: 1rem;
}
.theme-editor-body {
padding: 1.5rem;
}
.theme-preset-colors {
grid-template-columns: repeat(4, 1fr);
}
.stats-content {
grid-template-columns: 1fr;
gap: 1.5rem;
padding: 1rem;
}
.stats-card {
padding: 1.5rem;
}
}
/* ==================== 其他样式保持不变 ==================== */
/* 这里包含所有其他现有的样式,如终端、天气、模态框等 */
/* 为了简洁,我只展示了主要的新增和修改的样式 */
/* 加载动画 */
@keyframes pulse {
0%, 100% {
opacity: 0.5;
}
50% {
opacity: 1;
}
}
.loading {
animation: pulse 1.5s ease-in-out infinite;
}
/* 昼夜切换按钮样式 */
.toggle-container {
position: relative;
width: 70px;
height: 35px;
margin-right: 15px;
}
.toggle-input {
display: none;
}
.toggle-label {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(145deg, #e6e6e6, #ffffff);
border-radius: 50px;
box-shadow:
0 4px 15px rgba(0, 0, 0, 0.1),
inset 0 2px 5px rgba(255, 255, 255, 0.5),
inset 0 -2px 5px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
overflow: hidden;
}
.dark-mode .toggle-label {
background: linear-gradient(145deg, #2a2a2a, #1e1e1e);
box-shadow:
0 4px 15px rgba(0, 0, 0, 0.3),
inset 0 2px 5px rgba(255, 255, 255, 0.05),
inset 0 -2px 5px rgba(0, 0, 0, 0.5);
}
.toggle-button {
position: absolute;
top: 3px;
left: 3px;
width: 29px;
height: 29px;
background: linear-gradient(145deg, #ffdf6b, #ffb347);
border-radius: 50%;
box-shadow:
0 2px 10px rgba(255, 179, 71, 0.5),
inset 0 1px 3px rgba(255, 255, 255, 0.4);
transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.dark-mode .toggle-button {
left: 38px;
background: linear-gradient(145deg, #d1d1d1, #f1f1f1);
box-shadow:
0 2px 10px rgba(209, 209, 209, 0.5),
inset 0 1px 3px rgba(255, 255, 255, 0.4);
}
.sun {
position: absolute;
width: 18px;
height: 18px;
border-radius: 50%;
background: #ffdf6b;
box-shadow:
0 0 5px #ffdf6b,
0 0 10px #ffdf6b,
0 0 15px #ffdf6b;
transition: all 0.5s ease;
opacity: 1;
}
.dark-mode .sun {
opacity: 0;
transform: scale(0.5);
}
.moon {
position: absolute;
width: 18px;
height: 18px;
border-radius: 50%;
background: #f1f1f1;
box-shadow:
inset -4px -1px 0 0 #d1d1d1;
transition: all 0.5s ease;
opacity: 0;
transform: scale(0.5) rotate(90deg);
}
.dark-mode .moon {
opacity: 1;
transform: scale(1) rotate(0deg);
}
.stars {
position: absolute;
width: 100%;
height: 100%;
background: transparent;
transition: all 0.5s ease;
}
.star {
position: absolute;
background-color: white;
border-radius: 50%;
opacity: 0;
transition: all 0.5s ease;
}
.dark-mode .star {
opacity: 1;
}
.star:nth-child(1) {
top: 15%;
left: 25%;
width: 1px;
height: 1px;
animation: twinkle 2s infinite alternate;
}
.star:nth-child(2) {
top: 25%;
left: 70%;
width: 2px;
height: 2px;
animation: twinkle 1.5s infinite alternate 0.5s;
}
.star:nth-child(3) {
top: 60%;
left: 40%;
width: 1px;
height: 1px;
animation: twinkle 2.5s infinite alternate 0.2s;
}
.star:nth-child(4) {
top: 75%;
left: 20%;
width: 2px;
height: 2px;
animation: twinkle 1.8s infinite alternate 0.7s;
}
.star:nth-child(5) {
top: 40%;
left: 80%;
width: 1px;
height: 1px;
animation: twinkle 2.2s infinite alternate 0.3s;
}
@keyframes twinkle {
0% { opacity: 0.3; }
100% { opacity: 1; }
}
.clouds {
position: absolute;
width: 100%;
height: 100%;
transition: all 0.5s ease;
}
.cloud {
position: absolute;
background-color: white;
border-radius: 50px;
opacity: 1;
transition: all 0.5s ease;
}
.dark-mode .cloud {
opacity: 0;
}
.cloud:nth-child(1) {
top: 20%;
left: 20%;
width: 12px;
height: 6px;
}
.cloud:nth-child(2) {
top: 30%;
left: 60%;
width: 18px;
height: 8px;
}
.cloud:nth-child(3) {
top: 70%;
left: 30%;
width: 15px;
height: 6px;
}
/* 模态框样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: none;
justify-content: center;
align-items: center;
z-index: 2000;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.modal-overlay.show {
display: flex;
}
.modal-content {
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 20px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
animation: modalSlideIn 0.3s ease;
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translateY(-50px) scale(0.9);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 2rem;
border-bottom: 1px solid var(--card-border);
}
.modal-header h3 {
color: var(--tab-text);
font-size: 1.25rem;
font-weight: 600;
}
.modal-close {
width: 32px;
height: 32px;
border: none;
background: transparent;
cursor: pointer;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: var(--startup-text-tertiary);
transition: all 0.3s ease;
}
.modal-close:hover {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
}
.modal-body {
padding: 2rem;
}
.form-group {
margin-bottom: 1.5rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
color: var(--tab-text);
font-weight: 500;
}
.form-group input,
.form-group select {
width: 100%;
padding: 12px 16px;
border: 1px solid var(--card-border);
border-radius: 12px;
background: var(--search-bg);
color: var(--tab-text);
font-size: 1rem;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
box-shadow: 0 0 0 3px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.1);
}
.form-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 2rem;
}
.btn-primary,
.btn-secondary {
padding: 12px 24px;
border-radius: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
border: none;
}
.btn-primary {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
box-shadow: 0 4px 12px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.4);
}
.btn-secondary {
background: transparent;
color: var(--tab-text);
border: 1px solid var(--card-border);
}
.btn-secondary:hover {
background: var(--card-bg);
transform: translateY(-2px);
}
/* 自定义网站管理样式 */
.custom-sites-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding: 0 0.5rem;
}
.custom-sites-title h3 {
color: var(--tab-text);
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.custom-sites-title p {
color: var(--startup-text-tertiary);
font-size: 0.9rem;
}
.add-site-btn {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
border: none;
border-radius: 12px;
padding: 12px 20px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
box-shadow: 0 4px 12px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.3);
}
.add-site-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.4);
}
.custom-site-card {
position: relative;
}
.custom-site-card .site-actions {
position: absolute;
top: 8px;
right: 8px;
display: flex;
gap: 4px;
opacity: 0;
transition: opacity 0.3s ease;
}
.custom-site-card:hover .site-actions {
opacity: 1;
}
.site-action-btn {
width: 24px;
height: 24px;
border: none;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
transition: all 0.3s ease;
}
.site-action-btn.edit {
background: rgba(59, 130, 246, 0.9);
color: white;
}
.site-action-btn.delete {
background: rgba(239, 68, 68, 0.9);
color: white;
}
.site-action-btn:hover {
transform: scale(1.1);
}
/* 终端样式 */
.terminal-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: var(--startup-bg);
background-image:
var(--startup-overlay),
radial-gradient(circle at 30% 40%, rgba(120, 119, 198, 0.15) 0%, transparent 50%),
radial-gradient(circle at 70% 80%, rgba(255, 119, 198, 0.1) 0%, transparent 50%),
linear-gradient(135deg, rgba(91, 155, 213, 0.05) 0%, rgba(255, 119, 198, 0.05) 100%);
animation: backgroundShift 20s ease-in-out infinite;
position: relative;
overflow: hidden;
}
.terminal-startup {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 10;
transition: all 0.5s ease;
color: var(--startup-text);
font-family: 'Inter', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.terminal-startup.hidden {
opacity: 0;
pointer-events: none;
transform: translateY(-20px);
}
.startup-logo {
font-size: 2.5rem;
font-weight: 600;
margin-bottom: 8px;
background: linear-gradient(135deg, var(--startup-accent), var(--startup-accent-hover), #ff6b9d);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: -0.02em;
animation: logoGlow 3s ease-in-out infinite alternate;
}
@keyframes logoGlow {
0% {
filter: drop-shadow(0 0 10px rgba(91, 155, 213, 0.3));
}
100% {
filter: drop-shadow(0 0 20px rgba(91, 155, 213, 0.6));
}
}
.startup-subtitle {
font-size: 1rem;
color: var(--startup-text-secondary);
font-weight: 400;
margin-bottom: 32px;
}
.startup-actions {
display: flex;
gap: 16px;
flex-wrap: wrap;
justify-content: center;
}
.startup-action-btn {
padding: 12px 24px;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: 12px;
color: var(--startup-text);
text-decoration: none;
transition: all 0.3s ease;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
}
.startup-action-btn:hover {
background: var(--startup-card-hover);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.startup-action-btn.primary {
background: var(--startup-accent);
color: white;
border-color: var(--startup-accent);
}
.startup-action-btn.primary:hover {
background: var(--startup-accent-hover);
border-color: var(--startup-accent-hover);
}
/* 编辑器主体 */
.editor {
width: 100%;
max-width: 1200px;
margin: 20px auto;
background: var(--editor-bg);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
transition: all var(--transition-normal);
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.1);
display: none;
flex-direction: column;
height: calc(100vh - 40px);
will-change: transform;
position: relative;
z-index: 5;
}
.editor.active {
display: flex;
}
.editor:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
}
.editor-header {
background: var(--header-bg);
padding: 12px;
border-radius: var(--border-radius) var(--border-radius) 0 0;
display: flex;
align-items: center;
gap: 8px;
transition: background-color var(--transition-normal);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.window-btn {
width: 12px;
height: 12px;
border-radius: 50%;
transition: all var(--transition-fast);
position: relative;
cursor: pointer;
}
.window-btn:hover::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6px;
height: 6px;
background: rgba(0, 0, 0, 0.3);
border-radius: 50%;
}
.close { background: var(--window-btn-close); }
.minimize {
background: var(--window-btn-minimize);
cursor: default;
opacity: 0.5;
}
.minimize:hover::after { display: none; }
.maximize { background: var(--window-btn-max); }
.title-bar {
color: var(--line-color);
margin-left: 20px;
font-size: 0.9em;
transition: color var(--transition-normal);
}
.editor-content {
padding: 20px;
counter-reset: line;
font-size: 14px;
overflow-x: auto;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--line-color) transparent;
flex: 1;
font-family: var(--font-family);
}
.editor-content::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.editor-content::-webkit-scrollbar-track {
background: transparent;
}
.editor-content::-webkit-scrollbar-thumb {
background-color: var(--line-color);
border-radius: 4px;
}
.line {
display: flex;
padding: 2px 0;
position: relative;
min-height: 1.6em;
}
.line::before {
counter-increment: line;
content: counter(line);
color: var(--line-color);
width: 2em;
text-align: right;
padding-right: 1em;
position: absolute;
transition: color var(--transition-normal);
opacity: 0.7;
}
.line-content {
padding-left: 3em;
width: 100%;
}
.indent { margin-left: 2em; }
.indent-2 { margin-left: 4em; }
.keyword { color: var(--keyword-color); }
.string { color: var(--string-color); }
.comment { color: var(--comment-color); }
.number { color: var(--number-color); }
.function { color: var(--function-color); }
.ai-output { color: var(--ai-output-color); }
.user-input { color: var(--user-input-color); }
a {
color: var(--accent-color);
text-decoration: none;
transition: all var(--transition-fast);
position: relative;
}
a:hover {
color: var(--accent-hover);
}
a::after {
content: '';
position: absolute;
width: 0;
height: 1px;
bottom: 0;
left: 0;
background-color: var(--accent-hover);
transition: width var(--transition-normal);
}
a:hover::after {
width: 100%;
}
.cursor {
display: inline-block;
width: 2px;
height: 1.2em;
background: var(--text-color);
margin-left: 2px;
animation: blink 1s step-end infinite;
vertical-align: middle;
transition: background var(--transition-normal);
}
@keyframes blink {
50% { opacity: 0; }
}
/* 输入行 */
.input-line {
display: flex;
align-items: center;
background: var(--editor-secondary-bg);
padding: 8px 10px;
border-radius: 4px;
transition: all var(--transition-normal);
margin: 0 20px 20px;
position: sticky;
bottom: 0;
z-index: 10;
}
.input-line:focus-within {
box-shadow: 0 0 0 2px var(--accent-color);
}
.input-line::before {
content: ">";
color: var(--accent-color);
width: 2em;
text-align: right;
padding-right: 1em;
font-weight: bold;
}
.input-line input {
flex: 1;
background: transparent;
border: none;
color: var(--text-color);
font-family: var(--font-family);
font-size: 14px;
outline: none;
padding: 2px 0;
}
/* 思考动画 */
.thinking-animation {
display: inline-block;
position: relative;
width: 60px;
height: 20px;
margin-left: 8px;
}
.thinking-animation span {
position: absolute;
width: 6px;
height: 6px;
background: var(--ai-output-color);
border-radius: 50%;
animation: thinking 1.4s infinite ease-in-out;
}
.thinking-animation span:nth-child(1) {
left: 0;
animation-delay: 0s;
}
.thinking-animation span:nth-child(2) {
left: 12px;
animation-delay: 0.2s;
}
.thinking-animation span:nth-child(3) {
left: 24px;
animation-delay: 0.4s;
}
@keyframes thinking {
0%, 80%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
40% {
transform: scale(1.2);
opacity: 1;
}
}
/* 命令面板样式 */
.command-palette {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
max-width: 600px;
background: var(--editor-bg);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
z-index: 1000;
display: none;
border: 1px solid rgba(255, 255, 255, 0.1);
max-height: 70vh;
overflow: hidden;
}
.command-palette-content {
padding: 15px;
max-height: calc(70vh - 50px);
overflow-y: auto;
}
.command-search {
width: 100%;
background: var(--editor-secondary-bg);
border: 1px solid var(--line-color);
color: var(--text-color);
padding: 12px 16px;
border-radius: 8px;
font-family: var(--font-family);
margin-bottom: 15px;
font-size: 14px;
transition: all var(--transition-normal);
}
.command-search:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 2px rgba(10, 132, 255, 0.3);
}
.command-search::placeholder {
color: var(--line-color);
}
.command-list {
max-height: 50vh;
overflow-y: auto;
}
.command-item {
padding: 12px 16px;
cursor: pointer;
border-radius: 6px;
display: flex;
align-items: center;
gap: 12px;
margin: 4px 0;
transition: all var(--transition-fast);
border: 1px solid transparent;
}
.command-item:hover {
background: var(--editor-secondary-bg);
border-color: var(--accent-color);
}
.command-item.selected {
background: var(--accent-color);
color: white;
}
.command-icon {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.command-content {
flex: 1;
min-width: 0;
}
.command-title {
font-weight: 500;
margin-bottom: 2px;
}
.command-description {
font-size: 0.85em;
opacity: 0.7;
line-height: 1.3;
}
.command-shortcut {
margin-left: auto;
color: var(--line-color);
font-size: 0.75em;
background: var(--editor-secondary-bg);
padding: 4px 8px;
border-radius: 4px;
font-family: var(--font-family);
}
.command-category {
font-size: 0.8em;
color: var(--accent-color);
padding: 8px 16px;
margin: 8px 0 4px 0;
border-top: 1px solid rgba(255, 255, 255, 0.1);
font-weight: 600;
}
.command-category:first-child {
border-top: none;
margin-top: 0;
}
/* ==================== 主题天气组合控件 ==================== */
.theme-weather-container {
display: flex;
align-items: center;
gap: 0.75rem;
margin-left: auto;
}
/* 调整天气部件样式 */
.theme-weather-container .weather-widget {
margin-left: 0;
padding: 0.5rem 0.75rem;
min-width: 0;
flex-shrink: 1;
}
/* 调整切换按钮容器 */
.theme-weather-container .toggle-container {
width: 50px;
height: 25px;
margin-right: 0;
flex-shrink: 0;
}
/* 调整切换按钮 */
.theme-weather-container .toggle-button {
width: 21px;
height: 21px;
top: 2px;
left: 2px;
}
.dark-mode .theme-weather-container .toggle-button {
left: 27px;
}
/* 天气图标调整 */
.theme-weather-container .weather-icon {
font-size: 1.25rem;
}
/* 移动端优化 */
@media (max-width: 768px) {
.theme-weather-container {
gap: 0.5rem;
}
.theme-weather-container .weather-widget {
padding: 0.375rem 0.5rem;
}
.theme-weather-container .weather-info {
display: none;
}
}
/* 底部备案信息 */
body.light-mode .footer {
background: rgba(255, 255, 255, 0.7);
border-top: 1px solid rgba(229, 231, 235, 0.5);
color: #6b7280;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
body.dark-mode .footer {
background: rgba(15, 23, 42, 0.7);
border-top: 1px solid rgba(255, 255, 255, 0.1);
color: #64748b;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 1rem;
text-align: center;
font-size: 0.75rem;
z-index: 10;
}
.footer a {
color: #818cf8;
text-decoration: none;
transition: color 0.2s ease;
}
.footer a:hover {
color: #6366f1;
text-decoration: underline;
}
/* iframe样式 */
body.light-mode .page-frame {
background: rgba(255, 255, 255, 0.8);
}
body.dark-mode .page-frame {
background: rgba(15, 23, 42, 0.8);
}
.page-frame {
width: 100%;
height: 100%;
border: none;
display: none;
border-radius: 0 0 var(--border-radius-size) var(--border-radius-size);
}
/* 天气详情页面样式 */
.weather-detail-container {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow-y: auto;
padding: 2rem;
}
.weather-detail-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 2rem;
color: white;
}
.back-btn {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
padding: 12px 16px;
color: white;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: flex;
align-items: center;
gap: 8px;
}
.back-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.weather-detail-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.weather-current {
grid-column: span 2;
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 24px;
padding: 3rem 2rem;
text-align: center;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
}
.current-temp {
font-size: 4rem;
font-weight: 300;
color: var(--tab-text);
margin-bottom: 1rem;
}
.current-desc {
font-size: 1.25rem;
color: var(--tab-text);
margin-bottom: 0.5rem;
}
.current-location {
font-size: 1rem;
color: var(--startup-text-tertiary);
}
.weather-forecast, .weather-details {
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 24px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--card-shadow);
}
.weather-forecast h3, .weather-details h3 {
color: var(--tab-text);
margin-bottom: 1.5rem;
font-size: 1.25rem;
font-weight: 600;
}
.forecast-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.forecast-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.forecast-day {
font-weight: 500;
color: var(--tab-text);
}
.forecast-icon {
font-size: 1.5rem;
color: var(--startup-accent);
}
.forecast-temp {
font-weight: 600;
color: var(--tab-text);
}
.detail-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.detail-item {
padding: 1rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
text-align: center;
}
.detail-label {
font-size: 0.875rem;
color: var(--startup-text-tertiary);
margin-bottom: 0.5rem;
}
.detail-value {
font-size: 1.25rem;
font-weight: 600;
color: var(--tab-text);
}
</style>
</head>
<body class="light-mode">
<div id="app">
<!-- 导航栏 -->
<nav>
<div class="top-nav">
<a href="#" class="nav-item" data-target="tools/image-cut" title="抠图工具">
<i class="fa-solid fa-cut text-lg"></i>
</a>
<a href="#" class="nav-item" data-target="tools/audio-parse" title="音频解析">
<i class="fa-solid fa-music text-lg"></i>
</a>
<a href="#" class="nav-item" data-target="network/ip-query" title="IP地址查询">
<i class="fa-solid fa-map-marker-alt text-lg"></i>
</a>
<a href="#" class="nav-item" data-target="media/gallery" title="图片画廊">
<i class="fa-solid fa-images text-lg"></i>
</a>
<a href="#" class="nav-item" data-target="terminal" title="个人终端">
<i class="fa-solid fa-terminal text-lg"></i>
</a>
</div>
<div class="side-nav">
<a href="#" class="nav-item" data-target="home" title="主页">
<i class="fa-solid fa-house text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="terminal" title="个人终端">
<i class="fa-solid fa-terminal text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="tools/image-cut" title="抠图工具">
<i class="fa-solid fa-cut text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="tools/audio-parse" title="音频解析">
<i class="fa-solid fa-music text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="network/ip-query" title="IP地址查询">
<i class="fa-solid fa-map-marker-alt text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="media/gallery" title="图片画廊">
<i class="fa-solid fa-images text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="content/blog" title="博客">
<i class="fa-solid fa-blog text-xl"></i>
</a>
<a href="#" class="nav-item" data-target="help/faq" title="常见问题">
<i class="fa-solid fa-question text-xl"></i>
</a>
</div>
</nav>
<!-- 内容区域 -->
<div id="content">
<header>
<button class="nav-toggle" aria-label="切换导航">
<i class="fa-solid fa-bars"></i>
</button>
<h1 class="ml-4 text-2xl font-bold" id="page-title">TENG YUAN</h1>
<!-- 昼夜切换按钮 -->
<div class="theme-weather-container">
<!-- 昼夜切换按钮 -->
<div class="toggle-container">
<input type="checkbox" id="toggle" class="toggle-input">
<label for="toggle" class="toggle-label">
<div class="toggle-button">
<div class="sun"></div>
<div class="moon"></div>
</div>
<div class="stars">
<div class="star"></div>
<div class="star"></div>
<div class="star"></div>
<div class="star"></div>
<div class="star"></div>
</div>
<div class="clouds">
<div class="cloud"></div>
<div class="cloud"></div>
<div class="cloud"></div>
</div>
</label>
</div>
<!-- 天气显示 -->
<div class="weather-widget" id="weather-widget">
<div class="weather-icon loading">
<i class="fas fa-cloud"></i>
</div>
<div class="weather-info">
<span class="weather-temp loading" style="width: 3rem; height: 1rem; background: #64748b; border-radius: 0.25rem;"></span>
<span class="welcome-message loading" style="width: 8rem; height: 0.75rem; background: #64748b; border-radius: 0.25rem;"></span>
</div>
</div>
</div>
</header>
<main>
<!-- 新主页内容 - Tab布局 -->
<div class="main-content" id="home">
<div class="home-container">
<!-- 搜索区域 -->
<div class="home-search-section">
<div class="home-search-container">
<div class="search-engine-selector" id="searchEngineSelector">
<button class="search-engine-btn active" data-engine="google" title="Google">
<i class="fab fa-google"></i>
</button>
<button class="search-engine-btn" data-engine="baidu" title="百度">
<i class="fas fa-search"></i>
</button>
<button class="search-engine-btn" data-engine="bing" title="Bing">
<i class="fab fa-microsoft"></i>
</button>
<button class="search-engine-btn" data-engine="duckduckgo" title="DuckDuckGo">
<i class="fas fa-duck"></i>
</button>
</div>
<div class="search-input-wrapper">
<i class="fas fa-search home-search-icon"></i>
<form id="home-search-form" action="https://www.google.com/search" method="get" target="_blank">
<input class="home-search-input" type="text" name="q" placeholder="搜索互联网,发现无限可能..." autofocus>
</form>
</div>
</div>
</div>
<!-- Tab导航 -->
<div class="home-tabs">
<div class="tab-nav">
<button class="tab-button active" data-tab="common">
<span>常用</span>
</button>
<button class="tab-button" data-tab="tools">
<span>工具</span>
</button>
<button class="tab-button" data-tab="entertainment">
<span>娱乐</span>
</button>
<button class="tab-button" data-tab="ai">
<span>AI助手</span>
</button>
<button class="tab-button" data-tab="dev">
<span>开发</span>
</button>
<button class="tab-button" data-tab="custom">
<span>自定义</span>
</button>
</div>
<div class="tab-actions">
<button class="tab-action-btn" id="addSiteBtn" title="添加网站">
<i class="fas fa-plus"></i>
</button>
<button class="tab-action-btn" id="themeEditorBtn" title="主题编辑器">
<i class="fas fa-palette"></i>
</button>
<button class="tab-action-btn" id="statsBtn" title="使用统计">
<i class="fas fa-chart-bar"></i>
</button>
</div>
</div>
<!-- Tab内容 -->
<div class="home-content">
<!-- 常用标签页 -->
<div class="tab-content active" id="tab-common">
<div class="quick-actions">
<div class="quick-action" data-target="terminal">
<div class="quick-action-icon">
<i class="fas fa-terminal"></i>
</div>
<div class="quick-action-name">终端</div>
</div>
<div class="quick-action" onclick="window.open('https://www.google.com', '_blank')">
<div class="quick-action-icon">
<i class="fab fa-google"></i>
</div>
<div class="quick-action-name">Google</div>
</div>
<div class="quick-action" onclick="window.open('https://www.baidu.com', '_blank')">
<div class="quick-action-icon">
<i class="fas fa-search"></i>
</div>
<div class="quick-action-name">百度</div>
</div>
<div class="quick-action" onclick="window.open('https://github.com', '_blank')">
<div class="quick-action-icon">
<i class="fab fa-github"></i>
</div>
<div class="quick-action-name">GitHub</div>
</div>
</div>
<div class="sites-grid">
<a href="https://www.google.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.google.com/favicon.ico" alt="Google" onerror="this.innerHTML='<i class="fab fa-google"></i>'">
</div>
<div class="site-name">Google</div>
<div class="site-desc">全球最大搜索引擎</div>
</a>
<a href="https://www.baidu.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.baidu.com/favicon.ico" alt="百度" onerror="this.innerHTML='<i class="fas fa-search"></i>'">
</div>
<div class="site-name">百度</div>
<div class="site-desc">中文搜索引擎</div>
</a>
<a href="https://github.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://github.com/favicon.ico" alt="GitHub" onerror="this.innerHTML='<i class="fab fa-github"></i>'">
</div>
<div class="site-name">GitHub</div>
<div class="site-desc">代码托管平台</div>
</a>
<a href="https://www.bilibili.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.bilibili.com/favicon.ico" alt="Bilibili" onerror="this.innerHTML='<i class="fas fa-play"></i>'">
</div>
<div class="site-name">Bilibili</div>
<div class="site-desc">弹幕视频网站</div>
</a>
<a href="https://www.zhihu.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.zhihu.com/favicon.ico" alt="知乎" onerror="this.innerHTML='<i class="fas fa-question-circle"></i>'">
</div>
<div class="site-name">知乎</div>
<div class="site-desc">知识问答社区</div>
</a>
<a href="https://weibo.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://weibo.com/favicon.ico" alt="微博" onerror="this.innerHTML='<i class="fab fa-weibo"></i>'">
</div>
<div class="site-name">微博</div>
<div class="site-desc">社交媒体平台</div>
</a>
</div>
</div>
<!-- 工具标签页 -->
<div class="tab-content" id="tab-tools">
<div class="sites-grid">
<div class="site-card feature-card" data-target="terminal">
<div class="site-icon">
<i class="fas fa-terminal"></i>
</div>
<div class="site-name">个人终端</div>
<div class="site-desc">强大的命令行工具,支持AI对话、编码工具等</div>
</div>
<a href="https://translate.google.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://translate.google.com/favicon.ico" alt="Google翻译" onerror="this.innerHTML='<i class="fas fa-language"></i>'">
</div>
<div class="site-name">Google翻译</div>
<div class="site-desc">多语言翻译工具</div>
</a>
<a href="https://www.canva.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.canva.com/favicon.ico" alt="Canva" onerror="this.innerHTML='<i class="fas fa-palette"></i>'">
</div>
<div class="site-name">Canva</div>
<div class="site-desc">在线设计工具</div>
</a>
<a href="https://www.figma.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.figma.com/favicon.ico" alt="Figma" onerror="this.innerHTML='<i class="fas fa-vector-square"></i>'">
</div>
<div class="site-name">Figma</div>
<div class="site-desc">UI/UX设计工具</div>
</a>
<a href="https://www.notion.so" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.notion.so/favicon.ico" alt="Notion" onerror="this.innerHTML='<i class="fas fa-sticky-note"></i>'">
</div>
<div class="site-name">Notion</div>
<div class="site-desc">笔记和协作工具</div>
</a>
<a href="https://www.photopea.com" class="site-card" target="_blank">
<div class="site-icon">
<i class="fas fa-image"></i>
</div>
<div class="site-name">Photopea</div>
<div class="site-desc">在线图片编辑器</div>
</a>
</div>
</div>
<!-- 娱乐标签页 -->
<div class="tab-content" id="tab-entertainment">
<div class="sites-grid">
<a href="https://www.youtube.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.youtube.com/favicon.ico" alt="YouTube" onerror="this.innerHTML='<i class="fab fa-youtube"></i>'">
</div>
<div class="site-name">YouTube</div>
<div class="site-desc">全球视频分享平台</div>
</a>
<a href="https://www.bilibili.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.bilibili.com/favicon.ico" alt="Bilibili" onerror="this.innerHTML='<i class="fas fa-play"></i>'">
</div>
<div class="site-name">Bilibili</div>
<div class="site-desc">弹幕视频网站</div>
</a>
<a href="https://music.163.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://music.163.com/favicon.ico" alt="网易云音乐" onerror="this.innerHTML='<i class="fas fa-music"></i>'">
</div>
<div class="site-name">网易云音乐</div>
<div class="site-desc">在线音乐平台</div>
</a>
<a href="https://www.spotify.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.spotify.com/favicon.ico" alt="Spotify" onerror="this.innerHTML='<i class="fab fa-spotify"></i>'">
</div>
<div class="site-name">Spotify</div>
<div class="site-desc">全球音乐流媒体</div>
</a>
<a href="https://www.netflix.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.netflix.com/favicon.ico" alt="Netflix" onerror="this.innerHTML='<i class="fas fa-film"></i>'">
</div>
<div class="site-name">Netflix</div>
<div class="site-desc">在线视频流媒体</div>
</a>
<a href="https://www.twitch.tv" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.twitch.tv/favicon.ico" alt="Twitch" onerror="this.innerHTML='<i class="fab fa-twitch"></i>'">
</div>
<div class="site-name">Twitch</div>
<div class="site-desc">游戏直播平台</div>
</a>
</div>
</div>
<!-- AI助手标签页 -->
<div class="tab-content" id="tab-ai">
<div class="sites-grid">
<div class="site-card feature-card" data-target="terminal">
<div class="site-icon">
<i class="fas fa-robot"></i>
</div>
<div class="site-name">内置AI助手</div>
<div class="site-desc">集成在终端中的智能AI助手,支持对话和编程辅助</div>
</div>
<a href="https://chat.openai.com" class="site-card" target="_blank">
<div class="site-icon">
<i class="fas fa-comments"></i>
</div>
<div class="site-name">ChatGPT</div>
<div class="site-desc">OpenAI智能对话助手</div>
</a>
<a href="https://claude.ai" class="site-card" target="_blank">
<div class="site-icon">
<i class="fas fa-brain"></i>
</div>
<div class="site-name">Claude</div>
<div class="site-desc">Anthropic AI助手</div>
</a>
<a href="https://www.midjourney.com" class="site-card" target="_blank">
<div class="site-icon">
<i class="fas fa-paint-brush"></i>
</div>
<div class="site-name">Midjourney</div>
<div class="site-desc">AI图像生成工具</div>
</a>
<a href="https://copilot.microsoft.com" class="site-card" target="_blank">
<div class="site-icon">
<i class="fab fa-microsoft"></i>
</div>
<div class="site-name">Copilot</div>
<div class="site-desc">微软AI助手</div>
</a>
<a href="https://v0.dev" class="site-card" target="_blank">
<div class="site-icon">
<i class="fas fa-code"></i>
</div>
<div class="site-name">v0.dev</div>
<div class="site-desc">AI代码生成工具</div>
</a>
</div>
</div>
<!-- 开发标签页 -->
<div class="tab-content" id="tab-dev">
<div class="sites-grid">
<a href="https://github.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://github.com/favicon.ico" alt="GitHub" onerror="this.innerHTML='<i class="fab fa-github"></i>'">
</div>
<div class="site-name">GitHub</div>
<div class="site-desc">代码托管平台</div>
</a>
<a href="https://stackoverflow.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://stackoverflow.com/favicon.ico" alt="Stack Overflow" onerror="this.innerHTML='<i class="fab fa-stack-overflow"></i>'">
</div>
<div class="site-name">Stack Overflow</div>
<div class="site-desc">程序员问答社区</div>
</a>
<a href="https://developer.mozilla.org" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://developer.mozilla.org/favicon.ico" alt="MDN" onerror="this.innerHTML='<i class="fab fa-firefox"></i>'">
</div>
<div class="site-name">MDN</div>
<div class="site-desc">Web开发文档</div>
</a>
<a href="https://www.npmjs.com" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://www.npmjs.com/favicon.ico" alt="npm" onerror="this.innerHTML='<i class="fab fa-npm"></i>'">
</div>
<div class="site-name">npm</div>
<div class="site-desc">Node.js包管理器</div>
</a>
<a href="https://codepen.io" class="site-card" target="_blank">
<div class="site-icon">
<img src="https://codepen.io/favicon.ico" alt="CodePen" onerror="this.innerHTML='<i class="fab fa-codepen"></i>'">
</div>
<div class="site-name">CodePen</div>
<div class="site-desc">在线代码编辑器</div>
</a>
<a href="https://vercel.com" class="site-card" target="_blank">
<div class="site-icon">
<i class="fas fa-rocket"></i>
</div>
<div class="site-name">Vercel</div>
<div class="site-desc">前端部署平台</div>
</a>
</div>
</div>
<!-- 自定义标签页 -->
<div class="tab-content" id="tab-custom">
<div class="custom-sites-header">
<div class="custom-sites-title">
<h3>我的自定义网站</h3>
<p>管理您的个人收藏网站</p>
</div>
<button class="add-site-btn" id="addCustomSiteBtn">
<i class="fas fa-plus"></i>
添加网站
</button>
</div>
<div class="sites-grid" id="customSitesGrid">
<!-- 自定义网站将通过JS动态添加 -->
</div>
</div>
</div>
</div>
</div>
<!-- 个人终端页面 -->
<div class="main-content" id="terminal">
<div class="terminal-container">
<!-- 终端起始页 -->
<div class="terminal-startup" id="terminalStartup">
<h1 class="startup-logo">藤原的个人终端</h1>
<p class="startup-subtitle">智能终端 · 高效工作 · 极致体验</p>
<div class="startup-actions">
<button class="startup-action-btn primary" id="startTerminalBtn">
<i class="fa-solid fa-terminal"></i> 启动终端
</button>
<button class="startup-action-btn" id="showHelpBtn">
<i class="fa-solid fa-question-circle"></i> 查看帮助
</button>
<button class="startup-action-btn" id="openCommandPaletteBtn">
<i class="fa-solid fa-palette"></i> 命令面板
</button>
</div>
</div>
<!-- 个人终端编辑器 -->
<div class="editor" id="mainEditor">
<div class="editor-header" id="editorHeader">
<span class="window-btn close" id="closeBtn"></span>
<span class="window-btn minimize" id="minimizeBtn"></span>
<span class="window-btn maximize" id="maximizeBtn"></span>
<span class="title-bar">terminal.js - 藤原的个人终端</span>
</div>
<div class="editor-content" id="editorContent">
<div class="line">
<div class="line-content"><span class="comment">// 个人信息配置</span></div>
</div>
<div class="line">
<div class="line-content"><span class="keyword">const</span> <span class="function">profile</span> = {</div>
</div>
<div class="line">
<div class="line-content indent"><span class="keyword">name</span>: <span class="string">"藤原"</span>,</div>
</div>
<div class="line">
<div class="line-content indent"><span class="keyword">title</span>: <span class="string">"职场牛马!!!"</span>,</div>
</div>
<div class="line">
<div class="line-content indent"><span class="keyword">contact</span>: {</div>
</div>
<div class="line">
<div class="line-content indent-2"><span class="keyword">email</span>: <span class="string"><a href="mailto:2083737075@qq.com">"2083737075@qq.com"</a></span>,</div>
</div>
<div class="line">
<div class="line-content indent-2"><span class="keyword">website</span>: <span class="string"><a href="http://tengyuan.icu" target="_blank">"TengYuan.icu"</a></span>,</div>
</div>
<div class="line">
<div class="line-content indent-2"><span class="keyword">FileCodeBox</span>: <span class="string"><a href="http://wp.tengyuan.icu/" target="_blank">"wp.tengyuan.icu"</a></span>,</div>
</div>
<div class="line">
<div class="line-content indent">},</div>
</div>
<div class="line">
<div class="line-content indent"><span class="keyword">links</span>: {</div>
</div>
<div class="line">
<div class="line-content indent-2"><span class="keyword">travel blog</span>: <span class="string"><a href="http://blog.tengyuan.icu/" target="_blank">"blog.tengyuan.icu"</a></span>,</div>
</div>
<div class="line">
<div class="line-content indent-2"><span class="keyword">birthday</span>: <span class="string"><a href="http://sr.0814.cn" target="_blank">"2001/11/01"</a></span>,</div>
</div>
<div class="line">
<div class="line-content indent">},</div>
</div>
<div class="line">
<div class="line-content indent"><span class="comment">// 座右铭</span></div>
</div>
<div class="line">
<div class="line-content indent"><span class="keyword">motto</span>: <span class="string">"以清简代码,筑玖维数字宇宙。"</span>,</div>
</div>
<div class="line">
<div class="line-content indent"><span class="keyword">copyright</span>: <span class="string">"2017-<span id="year"></span> 藤原"</span>,</div>
</div>
<div class="line">
<div class="line-content">};</div>
</div>
<div class="line">
<div class="line-content"><span class="comment">// 终端交互</span></div>
</div>
<div class="line">
<div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"欢迎访问藤原的个人终端"</span>);</div>
</div>
<div class="line">
<div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"输入 'help' 获取可用命令"</span>);</div>
</div>
</div>
<!-- 输入行 -->
<div class="input-line">
<input type="text" id="userInput" placeholder="输入命令..." autocomplete="off">
</div>
</div>
</div>
</div>
<!-- 天气详情页面 -->
<div class="main-content" id="weather-detail">
<div class="weather-detail-container">
<div class="weather-detail-header">
<button class="back-btn" onclick="pageManager.loadPage('home')">
<i class="fas fa-arrow-left"></i>
返回主页
</button>
<h2>天气详情</h2>
</div>
<div class="weather-detail-content" id="weatherDetailContent">
<div class="weather-current">
<div class="current-temp">--°C</div>
<div class="current-desc">加载中...</div>
<div class="current-location">定位中...</div>
</div>
<div class="weather-forecast">
<h3>未来天气</h3>
<div class="forecast-list" id="forecastList">
<!-- 天气预报项目将通过JS动态添加 -->
</div>
</div>
<div class="weather-details">
<h3>详细信息</h3>
<div class="detail-grid" id="weatherDetailGrid">
<!-- 详细信息将通过JS动态添加 -->
</div>
</div>
</div>
</div>
</div>
<!-- 使用统计页面 -->
<div class="main-content" id="stats">
<div class="stats-container">
<div class="stats-header">
<button class="back-btn" onclick="pageManager.loadPage('home')">
<i class="fas fa-arrow-left"></i>
返回主页
</button>
<h2>使用统计</h2>
</div>
<div class="stats-content">
<div class="stats-card">
<h3><i class="fas fa-mouse-pointer"></i> 功能使用统计</h3>
<div id="featureStats">
<!-- 功能统计将通过JS动态添加 -->
</div>
</div>
<div class="stats-card">
<h3><i class="fas fa-search"></i> 搜索引擎使用</h3>
<div id="searchEngineStats">
<!-- 搜索引擎统计将通过JS动态添加 -->
</div>
</div>
<div class="stats-card">
<h3><i class="fas fa-clock"></i> 使用时间分布</h3>
<div class="stats-chart" id="timeChart">
时间分布图表(开发中)
</div>
</div>
<div class="stats-card">
<h3><i class="fas fa-palette"></i> 主题使用情况</h3>
<div id="themeStats">
<!-- 主题统计将通过JS动态添加 -->
</div>
</div>
</div>
</div>
</div>
<!-- 其他页面的iframe容器 -->
<iframe id="tools/image-cut" class="page-frame" data-title="抠图工具"></iframe>
<iframe id="tools/audio-parse" class="page-frame" data-title="音频解析"></iframe>
<iframe id="network/ip-query" class="page-frame" data-title="IP地址查询"></iframe>
<iframe id="media/gallery" class="page-frame" data-title="图片画廊"></iframe>
<iframe id="content/blog" class="page-frame" data-title="博客"></iframe>
<iframe id="help/faq" class="page-frame" data-title="常见问题"></iframe>
</main>
<!-- 底部备案信息 -->
<div class="footer">
<p>© 2025 TENG YUAN | <a href="#" target="_blank">隐私政策</a> | <a href="#" target="_blank">服务条款</a> | <a href="https://beian.miit.gov.cn/" target="_blank">ICP备案号</a></p>
</div>
</div>
</div>
<!-- 命令面板 -->
<div class="command-palette" id="commandPalette">
<div class="editor-header">
<span class="window-btn close" id="closeCommandPaletteBtn"></span>
<span class="window-btn minimize"></span>
<span class="window-btn maximize"></span>
<span class="title-bar">command-palette.js - 命令面板</span>
</div>
<div class="command-palette-content">
<input type="text" class="command-search" id="commandSearch" placeholder="搜索命令...">
<div class="command-list" id="commandList">
<!-- 命令将通过JS动态添加 -->
</div>
</div>
</div>
<!-- 主题编辑器 -->
<div class="theme-editor" id="themeEditor">
<div class="theme-editor-header">
<h3>主题编辑器</h3>
<button class="theme-editor-close" id="closeThemeEditor">
<i class="fas fa-times"></i>
</button>
</div>
<div class="theme-editor-body">
<div class="theme-control-group">
<label>主色调</label>
<input type="range" class="theme-slider" id="hueSlider" min="0" max="360" value="243">
<div class="theme-value-display">
<span>色相</span>
<span id="hueValue">243°</span>
</div>
</div>
<div class="theme-control-group">
<label>饱和度</label>
<input type="range" class="theme-slider" id="saturationSlider" min="0" max="100" value="75">
<div class="theme-value-display">
<span>饱和度</span>
<span id="saturationValue">75%</span>
</div>
</div>
<div class="theme-control-group">
<label>亮度</label>
<input type="range" class="theme-slider" id="lightnessSlider" min="30" max="80" value="59">
<div class="theme-value-display">
<span>亮度</span>
<span id="lightnessValue">59%</span>
</div>
</div>
<div class="theme-control-group">
<label>背景透明度</label>
<input type="range" class="theme-slider" id="opacitySlider" min="0.5" max="1" step="0.05" value="0.85">
<div class="theme-value-display">
<span>透明度</span>
<span id="opacityValue">85%</span>
</div>
</div>
<div class="theme-control-group">
<label>模糊强度</label>
<input type="range" class="theme-slider" id="blurSlider" min="0" max="30" value="12">
<div class="theme-value-display">
<span>模糊</span>
<span id="blurValue">12px</span>
</div>
</div>
<div class="theme-control-group">
<label>圆角大小</label>
<input type="range" class="theme-slider" id="radiusSlider" min="0" max="3" step="0.1" value="1.5">
<div class="theme-value-display">
<span>圆角</span>
<span id="radiusValue">1.5rem</span>
</div>
</div>
<div class="theme-control-group">
<label>预设颜色</label>
<div class="theme-preset-colors">
<div class="theme-preset-color" style="background: #6366f1" data-hue="243" data-saturation="75" data-lightness="59"></div>
<div class="theme-preset-color" style="background: #ef4444" data-hue="0" data-saturation="84" data-lightness="60"></div>
<div class="theme-preset-color" style="background: #10b981" data-hue="160" data-saturation="84" data-lightness="39"></div>
<div class="theme-preset-color" style="background: #f59e0b" data-hue="45" data-saturation="93" data-lightness="47"></div>
<div class="theme-preset-color" style="background: #8b5cf6" data-hue="262" data-saturation="83" data-lightness="58"></div>
<div class="theme-preset-color" style="background: #06b6d4" data-hue="188" data-saturation="94" data-lightness="42"></div>
</div>
</div>
<div class="theme-actions">
<button class="theme-btn theme-btn-secondary" id="resetThemeBtn">重置</button>
<button class="theme-btn theme-btn-primary" id="saveThemeBtn">保存主题</button>
</div>
</div>
</div>
<!-- 添加网站模态框 -->
<div class="modal-overlay" id="addSiteModal">
<div class="modal-content">
<div class="modal-header">
<h3>添加自定义网站</h3>
<button class="modal-close" id="closeAddSiteModal">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<form id="addSiteForm">
<div class="form-group">
<label for="siteName">网站名称</label>
<input type="text" id="siteName" placeholder="输入网站名称" required>
</div>
<div class="form-group">
<label for="siteUrl">网站地址</label>
<input type="url" id="siteUrl" placeholder="https://example.com" required>
</div>
<div class="form-group">
<label for="siteDesc">网站描述</label>
<input type="text" id="siteDesc" placeholder="网站简短描述">
</div>
<div class="form-group">
<label for="siteIcon">图标</label>
<select id="siteIcon">
<option value="fas fa-globe">🌐 网站</option>
<option value="fas fa-shopping-cart">🛒 购物</option>
<option value="fas fa-music">🎵 音乐</option>
<option value="fas fa-video">📹 视频</option>
<option value="fas fa-book">📚 学习</option>
<option value="fas fa-gamepad">🎮 游戏</option>
<option value="fas fa-newspaper">📰 新闻</option>
<option value="fas fa-camera">📷 图片</option>
<option value="fas fa-code">💻 技术</option>
</select>
</div>
<div class="form-actions">
<button type="button" class="btn-secondary" id="cancelAddSite">取消</button>
<button type="submit" class="btn-primary">添加网站</button>
</div>
</form>
</div>
</div>
</div>
<!-- 隐藏的文件输入元素 -->
<input type="file" id="fileInput" accept="image/*" style="display: none;">
<script>
// ==================== 使用统计管理器 ====================
const usageStats = {
init: function() {
this.loadStats();
this.setupEventListeners();
},
setupEventListeners: function() {
// 监听页面切换
document.addEventListener('click', (e) => {
if (e.target.matches('[data-target]')) {
this.recordFeatureUsage(e.target.dataset.target);
}
});
// 监听搜索引擎切换
document.addEventListener('click', (e) => {
if (e.target.matches('.search-engine-btn')) {
this.recordSearchEngineUsage(e.target.dataset.engine);
}
});
// 监听主题切换
document.addEventListener('change', (e) => {
if (e.target.id === 'toggle') {
this.recordThemeUsage(document.body.classList.contains('dark-mode') ? 'dark' : 'light');
}
});
},
recordFeatureUsage: function(feature) {
const stats = this.getStats();
const today = new Date().toDateString();
if (!stats.features[feature]) {
stats.features[feature] = { count: 0, lastUsed: today };
}
stats.features[feature].count++;
stats.features[feature].lastUsed = today;
this.saveStats(stats);
},
recordSearchEngineUsage: function(engine) {
const stats = this.getStats();
const today = new Date().toDateString();
if (!stats.searchEngines[engine]) {
stats.searchEngines[engine] = { count: 0, lastUsed: today };
}
stats.searchEngines[engine].count++;
stats.searchEngines[engine].lastUsed = today;
this.saveStats(stats);
},
recordThemeUsage: function(theme) {
const stats = this.getStats();
const today = new Date().toDateString();
if (!stats.themes[theme]) {
stats.themes[theme] = { count: 0, lastUsed: today };
}
stats.themes[theme].count++;
stats.themes[theme].lastUsed = today;
this.saveStats(stats);
},
getStats: function() {
const defaultStats = {
features: {},
searchEngines: {},
themes: {},
sessions: [],
totalUsageTime: 0
};
return JSON.parse(localStorage.getItem('usageStats') || JSON.stringify(defaultStats));
},
saveStats: function(stats) {
localStorage.setItem('usageStats', JSON.stringify(stats));
},
loadStats: function() {
this.renderStats();
},
renderStats: function() {
const stats = this.getStats();
// 渲染功能使用统计
this.renderFeatureStats(stats.features);
// 渲染搜索引擎统计
this.renderSearchEngineStats(stats.searchEngines);
// 渲染主题统计
this.renderThemeStats(stats.themes);
},
renderFeatureStats: function(features) {
const container = document.getElementById('featureStats');
if (!container) return;
const sortedFeatures = Object.entries(features)
.sort(([,a], [,b]) => b.count - a.count)
.slice(0, 10);
if (sortedFeatures.length === 0) {
container.innerHTML = '<div class="stats-item"><span class="stats-item-label">暂无使用记录</span></div>';
return;
}
container.innerHTML = sortedFeatures.map(([feature, data]) => `
<div class="stats-item">
<span class="stats-item-label">${this.getFeatureName(feature)}</span>
<span class="stats-item-value">${data.count}次</span>
</div>
`).join('');
},
renderSearchEngineStats: function(engines) {
const container = document.getElementById('searchEngineStats');
if (!container) return;
const sortedEngines = Object.entries(engines)
.sort(([,a], [,b]) => b.count - a.count);
if (sortedEngines.length === 0) {
container.innerHTML = '<div class="stats-item"><span class="stats-item-label">暂无搜索记录</span></div>';
return;
}
container.innerHTML = sortedEngines.map(([engine, data]) => `
<div class="stats-item">
<span class="stats-item-label">${this.getEngineName(engine)}</span>
<span class="stats-item-value">${data.count}次</span>
</div>
`).join('');
},
renderThemeStats: function(themes) {
const container = document.getElementById('themeStats');
if (!container) return;
const sortedThemes = Object.entries(themes)
.sort(([,a], [,b]) => b.count - a.count);
if (sortedThemes.length === 0) {
container.innerHTML = '<div class="stats-item"><span class="stats-item-label">暂无主题切换记录</span></div>';
return;
}
container.innerHTML = sortedThemes.map(([theme, data]) => `
<div class="stats-item">
<span class="stats-item-label">${theme === 'dark' ? '深色模式' : '浅色模式'}</span>
<span class="stats-item-value">${data.count}次</span>
</div>
`).join('');
},
getFeatureName: function(feature) {
const names = {
'home': '主页',
'terminal': '个人终端',
'weather-detail': '天气详情',
'stats': '使用统计',
'tools/image-cut': '抠图工具',
'tools/audio-parse': '音频解析',
'network/ip-query': 'IP查询',
'media/gallery': '图片画廊',
'content/blog': '博客',
'help/faq': '常见问题'
};
return names[feature] || feature;
},
getEngineName: function(engine) {
const names = {
'google': 'Google',
'baidu': '百度',
'bing': 'Bing',
'duckduckgo': 'DuckDuckGo'
};
return names[engine] || engine;
}
};
// ==================== 主题编辑器管理器 ====================
const themeEditor = {
init: function() {
this.setupEventListeners();
this.loadSavedTheme();
},
setupEventListeners: function() {
const themeEditorBtn = document.getElementById('themeEditorBtn');
const closeThemeEditor = document.getElementById('closeThemeEditor');
const hueSlider = document.getElementById('hueSlider');
const saturationSlider = document.getElementById('saturationSlider');
const lightnessSlider = document.getElementById('lightnessSlider');
const opacitySlider = document.getElementById('opacitySlider');
const blurSlider = document.getElementById('blurSlider');
const radiusSlider = document.getElementById('radiusSlider');
const resetThemeBtn = document.getElementById('resetThemeBtn');
const saveThemeBtn = document.getElementById('saveThemeBtn');
const presetColors = document.querySelectorAll('.theme-preset-color');
themeEditorBtn.addEventListener('click', () => this.showThemeEditor());
closeThemeEditor.addEventListener('click', () => this.hideThemeEditor());
hueSlider.addEventListener('input', (e) => this.updateTheme('hue', e.target.value));
saturationSlider.addEventListener('input', (e) => this.updateTheme('saturation', e.target.value));
lightnessSlider.addEventListener('input', (e) => this.updateTheme('lightness', e.target.value));
opacitySlider.addEventListener('input', (e) => this.updateTheme('opacity', e.target.value));
blurSlider.addEventListener('input', (e) => this.updateTheme('blur', e.target.value));
radiusSlider.addEventListener('input', (e) => this.updateTheme('radius', e.target.value));
resetThemeBtn.addEventListener('click', () => this.resetTheme());
saveThemeBtn.addEventListener('click', () => this.saveTheme());
presetColors.forEach(color => {
color.addEventListener('click', () => this.applyPresetColor(color));
});
// 点击外部关闭
document.addEventListener('click', (e) => {
if (e.target.id === 'themeEditor') {
this.hideThemeEditor();
}
});
},
showThemeEditor: function() {
document.getElementById('themeEditor').classList.add('show');
this.updateValueDisplays();
},
hideThemeEditor: function() {
document.getElementById('themeEditor').classList.remove('show');
},
updateTheme: function(property, value) {
const root = document.documentElement;
switch(property) {
case 'hue':
root.style.setProperty('--primary-hue', value);
document.getElementById('hueValue').textContent = value + '°';
break;
case 'saturation':
root.style.setProperty('--primary-saturation', value + '%');
document.getElementById('saturationValue').textContent = value + '%';
break;
case 'lightness':
root.style.setProperty('--primary-lightness', value + '%');
document.getElementById('lightnessValue').textContent = value + '%';
break;
case 'opacity':
root.style.setProperty('--background-opacity', value);
document.getElementById('opacityValue').textContent = Math.round(value * 100) + '%';
break;
case 'blur':
root.style.setProperty('--blur-strength', value + 'px');
document.getElementById('blurValue').textContent = value + 'px';
break;
case 'radius':
root.style.setProperty('--border-radius-size', value + 'rem');
document.getElementById('radiusValue').textContent = value + 'rem';
break;
}
this.updatePresetColorSelection();
},
updateValueDisplays: function() {
const root = document.documentElement;
const computedStyle = getComputedStyle(root);
const hue = computedStyle.getPropertyValue('--primary-hue').trim();
const saturation = computedStyle.getPropertyValue('--primary-saturation').trim();
const lightness = computedStyle.getPropertyValue('--primary-lightness').trim();
const opacity = computedStyle.getPropertyValue('--background-opacity').trim();
const blur = computedStyle.getPropertyValue('--blur-strength').trim();
const radius = computedStyle.getPropertyValue('--border-radius-size').trim();
document.getElementById('hueSlider').value = hue;
document.getElementById('saturationSlider').value = saturation.replace('%', '');
document.getElementById('lightnessSlider').value = lightness.replace('%', '');
document.getElementById('opacitySlider').value = opacity;
document.getElementById('blurSlider').value = blur.replace('px', '');
document.getElementById('radiusSlider').value = radius.replace('rem', '');
document.getElementById('hueValue').textContent = hue + '°';
document.getElementById('saturationValue').textContent = saturation;
document.getElementById('lightnessValue').textContent = lightness;
document.getElementById('opacityValue').textContent = Math.round(opacity * 100) + '%';
document.getElementById('blurValue').textContent = blur;
document.getElementById('radiusValue').textContent = radius;
this.updatePresetColorSelection();
},
applyPresetColor: function(colorElement) {
const hue = colorElement.dataset.hue;
const saturation = colorElement.dataset.saturation;
const lightness = colorElement.dataset.lightness;
document.getElementById('hueSlider').value = hue;
document.getElementById('saturationSlider').value = saturation;
document.getElementById('lightnessSlider').value = lightness;
this.updateTheme('hue', hue);
this.updateTheme('saturation', saturation);
this.updateTheme('lightness', lightness);
this.updatePresetColorSelection();
},
updatePresetColorSelection: function() {
const currentHue = document.getElementById('hueSlider').value;
const currentSaturation = document.getElementById('saturationSlider').value;
const currentLightness = document.getElementById('lightnessSlider').value;
document.querySelectorAll('.theme-preset-color').forEach(color => {
const isActive = color.dataset.hue == currentHue &&
color.dataset.saturation == currentSaturation &&
color.dataset.lightness == currentLightness;
color.classList.toggle('active', isActive);
});
},
resetTheme: function() {
const defaults = {
hue: 243,
saturation: 75,
lightness: 59,
opacity: 0.85,
blur: 12,
radius: 1.5
};
Object.entries(defaults).forEach(([property, value]) => {
this.updateTheme(property, value);
switch(property) {
case 'hue':
document.getElementById('hueSlider').value = value;
break;
case 'saturation':
document.getElementById('saturationSlider').value = value;
break;
case 'lightness':
document.getElementById('lightnessSlider').value = value;
break;
case 'opacity':
document.getElementById('opacitySlider').value = value;
break;
case 'blur':
document.getElementById('blurSlider').value = value;
break;
case 'radius':
document.getElementById('radiusSlider').value = value;
break;
}
});
this.showNotification('主题已重置为默认设置', 'success');
},
saveTheme: function() {
const theme = {
hue: document.getElementById('hueSlider').value,
saturation: document.getElementById('saturationSlider').value,
lightness: document.getElementById('lightnessSlider').value,
opacity: document.getElementById('opacitySlider').value,
blur: document.getElementById('blurSlider').value,
radius: document.getElementById('radiusSlider').value
};
localStorage.setItem('customTheme', JSON.stringify(theme));
this.showNotification('主题设置已保存', 'success');
},
loadSavedTheme: function() {
const savedTheme = localStorage.getItem('customTheme');
if (savedTheme) {
const theme = JSON.parse(savedTheme);
Object.entries(theme).forEach(([property, value]) => {
this.updateTheme(property, value);
});
}
},
showNotification: function(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'success' ? '#10b981' : '#6366f1'};
color: white;
padding: 12px 20px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 3000;
animation: slideInRight 0.3s ease;
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.style.animation = 'slideOutRight 0.3s ease';
setTimeout(() => notification.remove(), 300);
}, 3000);
}
};
// ==================== 主题管理功能 ====================
const themeManager = {
init: function() {
const savedTheme = localStorage.getItem('theme');
if (!savedTheme) {
this.autoSetThemeByTime();
} else {
this.setTheme(savedTheme);
}
document.getElementById('toggle').addEventListener('change', this.toggleTheme.bind(this));
setInterval(this.autoSetThemeByTime.bind(this), 3600000);
const toggle = document.getElementById('toggle');
toggle.checked = document.body.classList.contains('dark-mode');
},
autoSetThemeByTime: function() {
const hour = new Date().getHours();
const isNightTime = hour >= 18 || hour < 6;
if (!localStorage.getItem('theme')) {
this.setTheme(isNightTime ? 'dark-mode' : 'light-mode');
document.getElementById('toggle').checked = isNightTime;
}
},
toggleTheme: function() {
const currentTheme = document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
const newTheme = currentTheme === 'dark-mode' ? 'light-mode' : 'dark-mode';
this.setTheme(newTheme);
localStorage.setItem('theme', newTheme);
// 记录主题使用统计
usageStats.recordThemeUsage(newTheme === 'dark-mode' ? 'dark' : 'light');
// 更新终端主题
this.updateTerminalTheme(newTheme);
},
setTheme: function(theme) {
document.body.classList.remove('light-mode', 'dark-mode');
document.body.classList.add(theme);
// 更新终端主题
this.updateTerminalTheme(theme);
},
updateTerminalTheme: function(theme) {
const terminalContainer = document.querySelector('.terminal-container');
if (terminalContainer) {
if (theme === 'light-mode') {
document.body.setAttribute('data-theme', 'light');
} else {
document.body.setAttribute('data-theme', 'dark');
}
}
}
};
// ==================== 每日一言功能 ====================
const dailyQuote = {
init: function() {
this.getQuote();
setInterval(this.getQuote.bind(this), 3600000);
},
getQuote: function() {
const apiUrl = 'https://v1.hitokoto.cn/?c=d&encode=text';
fetch(apiUrl)
.then(response => {
if (!response.ok) throw new Error('网络响应不正常');
return response.text();
})
.then(quote => {
this.updateDisplays(quote);
})
.catch(error => {
console.error('获取每日一言失败:', error);
const fallback = this.fallbackQuotes[
Math.floor(Math.random() * this.fallbackQuotes.length)
];
this.updateDisplays(fallback);
});
},
updateDisplays: function(quote) {
const containers = document.querySelectorAll('[id^="daily-quote-container"]');
containers.forEach(container => {
container.textContent = quote;
container.style.opacity = 0;
setTimeout(() => container.style.opacity = 1, 100);
});
},
fallbackQuotes: [
"不积跬步,无以至千里",
"学而不思则罔,思而不学则殆",
"生活就像海洋,只有意志坚强的人才能到达彼岸",
"今日事,今日毕"
]
};
// ==================== 天气功能 ====================
const weatherWidget = {
init: function() {
this.getWeather();
setInterval(this.getWeather.bind(this), 3600000);
},
getWeather: function() {
const apiUrl = 'https://api.kxzjoker.cn/api/Weather';
fetch(apiUrl)
.then(response => {
if (!response.ok) throw new Error('网络响应不正常');
return response.json();
})
.then(data => {
if (data.code !== 200) throw new Error('API返回错误');
let location = '欢迎访问本服务';
if (data.data && data.data.ipdata && data.data.ipdata.info) {
const locationParts = data.data.ipdata.info.split('-');
location = `👏欢迎来自${locationParts[0]}的用户`;
}
let weatherData = {
temp: '未知温度',
condition: 'cloud',
location: location
};
if (data.data && data.data.tianqi && data.data.tianqi.temperature) {
weatherData.temp = `${data.data.tianqi.temperature}°C`;
const weatherText = data.data.tianqi.weather.toLowerCase();
if (weatherText.includes('晴')) {
weatherData.condition = 'sun';
} else if (weatherText.includes('云') || weatherText.includes('阴')) {
weatherData.condition = 'cloud';
} else if (weatherText.includes('雨')) {
weatherData.condition = 'cloud-rain';
} else if (weatherText.includes('雪')) {
weatherData.condition = 'snowflake';
} else if (weatherText.includes('雷')) {
weatherData.condition = 'bolt';
} else if (weatherText.includes('雾')) {
weatherData.condition = 'smog';
}
}
this.updateDisplay(weatherData);
})
.catch(error => {
console.error('获取天气信息失败:', error);
const defaultWeather = {
temp: '未知天气',
condition: 'cloud',
location: '👏欢迎访问本服务'
};
this.updateDisplay(defaultWeather);
});
},
updateDisplay: function(data) {
const widget = document.getElementById('weather-widget');
const icon = widget.querySelector('.weather-icon i');
const temp = widget.querySelector('.weather-temp');
const location = widget.querySelector('.welcome-message');
widget.querySelector('.weather-icon').classList.remove('loading');
widget.querySelector('.weather-temp').classList.remove('loading');
widget.querySelector('.welcome-message').classList.remove('loading');
if (icon) {
icon.className = `fas fa-${data.condition}`;
}
if (temp) {
temp.textContent = data.temp;
temp.style.width = 'auto';
temp.style.height = 'auto';
temp.style.background = 'transparent';
}
if (location) {
location.textContent = data.location;
location.style.width = 'auto';
location.style.height = 'auto';
location.style.background = 'transparent';
}
widget.style.opacity = 0;
setTimeout(() => widget.style.opacity = 1, 300);
}
};
// ==================== 主页Tab功能 ====================
const homeTabManager = {
init: function() {
this.setupTabNavigation();
this.setupQuickActions();
},
setupTabNavigation: function() {
const tabButtons = document.querySelectorAll('.tab-button');
const tabContents = document.querySelectorAll('.tab-content');
tabButtons.forEach(button => {
button.addEventListener('click', () => {
const targetTab = button.dataset.tab;
// 移除所有活动状态
tabButtons.forEach(btn => btn.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
// 添加活动状态
button.classList.add('active');
document.getElementById(`tab-${targetTab}`).classList.add('active');
// 记录使用统计
usageStats.recordFeatureUsage(`tab-${targetTab}`);
});
});
},
setupQuickActions: function() {
const quickActions = document.querySelectorAll('.quick-action[data-target]');
const siteCards = document.querySelectorAll('.site-card[data-target]');
[...quickActions, ...siteCards].forEach(action => {
action.addEventListener('click', (e) => {
e.preventDefault();
const target = action.dataset.target;
if (target) {
pageManager.loadPage(target);
}
});
});
}
};
// ==================== 终端功能 ====================
const terminal = {
init: function() {
this.setupEventListeners();
this.initCommands();
this.commandHistory = JSON.parse(localStorage.getItem('commandHistory') || '[]');
this.historyIndex = -1;
// 设置当前年份
const currentYear = new Date().getFullYear();
const yearElement = document.getElementById('year');
if (yearElement) {
yearElement.textContent = currentYear;
}
},
setupEventListeners: function() {
const startTerminalBtn = document.getElementById('startTerminalBtn');
const showHelpBtn = document.getElementById('showHelpBtn');
const openCommandPaletteBtn = document.getElementById('openCommandPaletteBtn');
const closeBtn = document.getElementById('closeBtn');
const maximizeBtn = document.getElementById('maximizeBtn');
const userInput = document.getElementById('userInput');
const closeCommandPaletteBtn = document.getElementById('closeCommandPaletteBtn');
if (startTerminalBtn) startTerminalBtn.addEventListener('click', () => this.showTerminal());
if (showHelpBtn) showHelpBtn.addEventListener('click', () => this.showHelp());
if (openCommandPaletteBtn) openCommandPaletteBtn.addEventListener('click', () => this.showCommandPalette());
if (closeBtn) closeBtn.addEventListener('click', () => this.hideTerminal());
if (maximizeBtn) maximizeBtn.addEventListener('click', () => this.toggleFullscreen());
if (closeCommandPaletteBtn) closeCommandPaletteBtn.addEventListener('click', () => this.hideCommandPalette());
if (userInput) {
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const command = userInput.value.trim();
if (command) {
this.processCommand(command);
userInput.value = '';
}
}
});
}
// 键盘快捷键
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'k') {
e.preventDefault();
this.showCommandPalette();
return;
}
if (e.ctrlKey && e.key === 'l') {
e.preventDefault();
this.clearTerminal();
return;
}
if (e.key === 'Escape') {
this.hideCommandPalette();
return;
}
// 命令历史导航
if (document.activeElement === userInput) {
if (e.key === 'ArrowUp' && this.commandHistory.length > 0) {
e.preventDefault();
if (this.historyIndex < this.commandHistory.length - 1) {
this.historyIndex++;
userInput.value = this.commandHistory[this.commandHistory.length - 1 - this.historyIndex];
}
} else if (e.key === 'ArrowDown' && this.historyIndex > -1) {
e.preventDefault();
this.historyIndex--;
if (this.historyIndex === -1) {
userInput.value = '';
} else {
userInput.value = this.commandHistory[this.commandHistory.length - 1 - this.historyIndex];
}
}
}
});
},
showTerminal: function() {
const terminalStartup = document.getElementById('terminalStartup');
const mainEditor = document.getElementById('mainEditor');
const userInput = document.getElementById('userInput');
if (terminalStartup) terminalStartup.classList.add('hidden');
if (mainEditor) mainEditor.classList.add('active');
if (userInput) userInput.focus();
// 添加欢迎消息
setTimeout(() => {
this.addAILine('欢迎来到藤原的个人终端!输入 "help" 获取可用命令。');
}, 500);
},
hideTerminal: function() {
const terminalStartup = document.getElementById('terminalStartup');
const mainEditor = document.getElementById('mainEditor');
if (terminalStartup) terminalStartup.classList.remove('hidden');
if (mainEditor) mainEditor.classList.remove('active');
},
toggleFullscreen: function() {
const editor = document.getElementById('mainEditor');
if (!document.fullscreenElement) {
editor.requestFullscreen().catch(err => {
this.addAILine(`全屏模式错误: ${err.message}`);
});
} else {
document.exitFullscreen();
}
},
showHelp: function() {
this.showTerminal();
setTimeout(() => {
this.addAILine(this.helpText);
}, 600);
},
showCommandPalette: function() {
const commandPalette = document.getElementById('commandPalette');
const commandSearch = document.getElementById('commandSearch');
if (commandPalette) {
commandPalette.style.display = 'block';
if (commandSearch) {
commandSearch.value = '';
commandSearch.focus();
}
this.filterCommands('');
}
},
hideCommandPalette: function() {
const commandPalette = document.getElementById('commandPalette');
const userInput = document.getElementById('userInput');
if (commandPalette) commandPalette.style.display = 'none';
if (userInput) userInput.focus();
},
initCommands: function() {
this.commands = [
{ id: 'help', name: '帮助', description: '显示帮助信息', shortcut: '?', category: '基础' },
{ id: 'clear', name: '清空终端', description: '清除终端内容', shortcut: 'Ctrl+L', category: '基础' },
{ id: 'history', name: '命令历史', description: '显示命令历史记录', shortcut: 'H', category: '基础' },
{ id: 'theme', name: '切换主题', description: '切换深色/浅色主题', shortcut: 'T', category: '基础' },
{ id: 'ai', name: 'AI助手', description: '与AI助手对话', args: 'message', category: '工具' },
{ id: 'base64', name: 'Base64编解码', description: '进行Base64编码或解码', args: 'encode/decode text', category: '工具' },
{ id: 'todo', name: '待办事项', description: '管理待办事项', args: 'add/list/done/remove', category: '新功能' },
{ id: 'weather', name: '天气查询', description: '查看天气信息', category: '新功能' },
{ id: 'ip', name: 'IP查询', description: '查询IP地址信息', category: '新功能' },
{ id: 'time', name: '时间信息', description: '显示详细时间信息', category: '新功能' },
{ id: 'qr', name: '二维码生成', description: '生成文本二维码', args: 'text', category: '新功能' },
{ id: 'calc', name: '计算器', description: '数学计算', args: 'expression', category: '新功能' }
];
this.helpText = `
可用命令:
基础命令:
- help: 显示帮助信息
- clear: 清空终端
- history: 显示命令历史记录
- theme: 切换深色/浅色主题
- 暗色: 切换到暗色主题
- 亮色: 切换到亮色主题
工具命令:
- ai [message]: 与AI助手对话
例如: ai 你好
- base64 [encode/decode] [text]: 进行Base64编码/解码
例如: base64 encode 你好世界
新功能:
- todo [add/list/done/remove]: 管理待办事项
例如: todo add 完成项目报告
- weather: 查看天气信息
- ip: 查询IP地址信息
- time: 显示详细时间信息
- qr [文本]: 生成二维码
- calc [表达式]: 数学计算
例如: calc 2+3*4
快捷键:
- Ctrl+K: 打开命令面板
- Ctrl+L: 清空终端
- 上/下箭头: 浏览命令历史
`;
this.initCommandPalette();
},
initCommandPalette: function() {
const commandList = document.getElementById('commandList');
const commandSearch = document.getElementById('commandSearch');
if (!commandList) return;
commandList.innerHTML = '';
const categories = [...new Set(this.commands.map(cmd => cmd.category))];
categories.forEach(category => {
const categoryCommands = this.commands.filter(cmd => cmd.category === category);
const categoryTitle = document.createElement('div');
categoryTitle.className = 'command-category';
categoryTitle.textContent = category;
commandList.appendChild(categoryTitle);
categoryCommands.forEach(cmd => {
const item = document.createElement('div');
item.className = 'command-item';
item.dataset.id = cmd.id;
item.dataset.category = cmd.category;
const icon = document.createElement('div');
icon.className = 'command-icon';
icon.innerHTML = this.getCommandIcon(cmd.id);
const content = document.createElement('div');
content.className = 'command-content';
const title = document.createElement('div');
title.className = 'command-title';
title.textContent = cmd.name;
const description = document.createElement('div');
description.className = 'command-description';
description.textContent = cmd.description;
content.appendChild(title);
content.appendChild(description);
const shortcut = document.createElement('div');
shortcut.className = 'command-shortcut';
shortcut.textContent = cmd.shortcut || '';
item.appendChild(icon);
item.appendChild(content);
item.appendChild(shortcut);
item.addEventListener('click', () => {
this.executeCommandFromPalette(cmd);
});
commandList.appendChild(item);
});
});
if (commandSearch) {
commandSearch.addEventListener('input', () => {
this.filterCommands(commandSearch.value);
});
}
},
getCommandIcon: function(cmdId) {
const icons = {
'help': '<i class="fas fa-question-circle"></i>',
'clear': '<i class="fas fa-trash"></i>',
'ai': '<i class="fas fa-robot"></i>',
'base64': '<i class="fas fa-code"></i>',
'history': '<i class="fas fa-history"></i>',
'theme': '<i class="fas fa-palette"></i>',
'todo': '<i class="fas fa-tasks"></i>',
'weather': '<i class="fas fa-cloud"></i>',
'ip': '<i class="fas fa-map-marker-alt"></i>',
'time': '<i class="fas fa-clock"></i>',
'qr': '<i class="fas fa-qrcode"></i>',
'calc': '<i class="fas fa-calculator"></i>'
};
return icons[cmdId] || '<i class="fas fa-terminal"></i>';
},
filterCommands: function(query) {
const items = document.querySelectorAll('.command-item');
const categories = document.querySelectorAll('.command-category');
query = query.toLowerCase();
let visibleCategories = new Set();
categories.forEach(category => {
category.style.display = 'none';
});
items.forEach(item => {
const cmd = this.commands.find(c => c.id === item.dataset.id);
if (!cmd) return;
const matchesName = cmd.name.toLowerCase().includes(query);
const matchesId = cmd.id.toLowerCase().includes(query);
const matchesDesc = cmd.description.toLowerCase().includes(query);
const matchesCategory = cmd.category.toLowerCase().includes(query);
if (matchesName || matchesId || matchesDesc || matchesCategory) {
item.style.display = 'flex';
visibleCategories.add(cmd.category);
} else {
item.style.display = 'none';
}
});
categories.forEach(category => {
if (visibleCategories.has(category.textContent)) {
category.style.display = 'block';
}
});
if (!query) {
categories.forEach(category => {
category.style.display = 'block';
});
}
},
executeCommandFromPalette: function(cmd) {
this.hideCommandPalette();
const userInput = document.getElementById('userInput');
if (!userInput) return;
switch(cmd.id) {
case 'help':
case 'clear':
case 'history':
case 'todo':
case 'theme':
case 'weather':
case 'ip':
case 'time':
userInput.value = cmd.id;
break;
case 'ai':
case 'base64':
case 'qr':
case 'calc':
userInput.value = cmd.id + ' ';
break;
default:
return;
}
userInput.focus();
if (['help', 'clear', 'history', 'todo', 'theme', 'weather', 'ip', 'time'].includes(cmd.id)) {
const event = new KeyboardEvent('keypress', {'key': 'Enter'});
userInput.dispatchEvent(event);
}
},
processCommand: function(command) {
const parts = command.split(' ');
const cmd = parts[0].toLowerCase();
const args = parts.slice(1).join(' ');
this.saveToHistory(command);
this.addUserLine(command);
// 记录命令使用统计
usageStats.recordFeatureUsage(`terminal-${cmd}`);
switch(cmd) {
case 'help':
this.addAILine(this.helpText);
break;
case 'clear':
this.clearTerminal();
break;
case 'ai':
if (!args) {
this.addAILine('请输入您想对AI说的话');
} else {
this.sendMessage(args);
}
break;
case 'base64':
this.handleBase64(args);
break;
case 'theme':
this.addAILine(this.switchTheme());
break;
case '暗色':
this.addAILine(this.switchTheme('暗色'));
break;
case '亮色':
this.addAILine(this.switchTheme('亮色'));
break;
case 'todo':
this.handleTodo(args);
break;
case 'weather':
this.addAILine('天气信息请查看右上角天气小组件,或点击进入详情页面');
break;
case 'ip':
this.handleIP();
break;
case 'time':
this.handleTime();
break;
case 'qr':
this.handleQR(args);
break;
case 'calc':
this.handleCalc(args);
break;
case 'history':
this.showHistory();
break;
default:
if (command) {
this.sendMessage(command);
}
}
},
handleIP: function() {
fetch('https://api.ipify.org?format=json')
.then(response => response.json())
.then(data => {
const ip = data.ip;
return fetch(`https://ipapi.co/${ip}/json/`);
})
.then(response => response.json())
.then(data => {
const info = `
IP地址信息:
- IP: ${data.ip}
- 国家: ${data.country_name} (${data.country})
- 地区: ${data.region}
- 城市: ${data.city}
- ISP: ${data.org}
- 时区: ${data.timezone}
- 经纬度: ${data.latitude}, ${data.longitude}
`;
this.addAILine(info);
})
.catch(error => {
this.addAILine('获取IP信息失败: ' + error.message);
});
},
handleTime: function() {
const now = new Date();
const timeInfo = `
当前时间信息:
- 本地时间: ${now.toLocaleString('zh-CN')}
- UTC时间: ${now.toUTCString()}
- 时间戳: ${now.getTime()}
- 星期: ${['日', '一', '二', '三', '四', '五', '六'][now.getDay()]}
- 年份第${Math.ceil((now - new Date(now.getFullYear(), 0, 1)) / (24 * 60 * 60 * 1000))}天
- 时区: ${Intl.DateTimeFormat().resolvedOptions().timeZone}
`;
this.addAILine(timeInfo);
},
handleQR: function(text) {
if (!text) {
this.addAILine('请提供要生成二维码的文本\n例如: qr https://example.com');
return;
}
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(text)}`;
this.addAILine(`二维码已生成: ${text}\n查看二维码: ${qrUrl}`);
},
handleCalc: function(expression) {
if (!expression) {
this.addAILine('请提供数学表达式\n例如: calc 2+3*4');
return;
}
try {
// 简单的数学表达式计算(安全起见,只允许基本运算)
const sanitized = expression.replace(/[^0-9+\-*/().\s]/g, '');
if (sanitized !== expression) {
this.addAILine('表达式包含非法字符,只允许数字和基本运算符');
return;
}
const result = Function('"use strict"; return (' + sanitized + ')')();
this.addAILine(`计算结果: ${expression} = ${result}`);
} catch (error) {
this.addAILine('计算错误: ' + error.message);
}
},
saveToHistory: function(command) {
if (this.commandHistory.length === 0 || this.commandHistory[this.commandHistory.length - 1] !== command) {
this.commandHistory.push(command);
if (this.commandHistory.length > 20) {
this.commandHistory.shift();
}
localStorage.setItem('commandHistory', JSON.stringify(this.commandHistory));
}
this.historyIndex = -1;
},
addUserLine: function(text) {
const line = document.createElement('div');
line.className = 'line';
const lineContent = document.createElement('div');
lineContent.className = 'line-content user-input';
lineContent.textContent = `> ${text}`;
line.appendChild(lineContent);
const editorContent = document.getElementById('editorContent');
if (editorContent) {
editorContent.appendChild(line);
this.scrollToBottom();
}
return line;
},
addAILine: async function(text) {
const line = document.createElement('div');
line.className = 'line';
const lineContent = document.createElement('div');
lineContent.className = 'line-content ai-output';
lineContent.textContent = '藤原: ';
line.appendChild(lineContent);
const editorContent = document.getElementById('editorContent');
if (editorContent) {
editorContent.appendChild(line);
this.scrollToBottom();
await this.typeWriterEffect(lineContent, text);
}
return line;
},
typeWriterEffect: function(element, text, speed = 10) {
return new Promise((resolve) => {
let i = 0;
const typing = () => {
if (i < text.length) {
element.textContent += text.charAt(i);
i++;
setTimeout(typing, speed);
} else {
const cursor = element.querySelector('.cursor');
if (cursor) cursor.remove();
resolve();
}
};
const cursorSpan = document.createElement('span');
cursorSpan.className = 'cursor';
element.appendChild(cursorSpan);
typing();
});
},
clearTerminal: function() {
const lines = document.querySelectorAll('.line');
lines.forEach(line => {
if (!line.classList.contains('input-line')) {
line.remove();
}
});
},
scrollToBottom: function() {
const editorContent = document.getElementById('editorContent');
if (editorContent) {
editorContent.scrollTop = editorContent.scrollHeight;
}
},
switchTheme: function(theme) {
if (theme === 'light' || theme === '亮色') {
document.body.classList.remove('dark-mode');
document.body.classList.add('light-mode');
document.body.setAttribute('data-theme', 'light');
localStorage.setItem('theme', 'light-mode');
document.getElementById('toggle').checked = false;
return '已切换到亮色主题';
} else if (theme === 'dark' || theme === '暗色') {
document.body.classList.remove('light-mode');
document.body.classList.add('dark-mode');
document.body.setAttribute('data-theme', 'dark');
localStorage.setItem('theme', 'dark-mode');
document.getElementById('toggle').checked = true;
return '已切换到暗色主题';
} else {
const currentTheme = document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
const newTheme = currentTheme === 'dark-mode' ? 'light-mode' : 'dark-mode';
document.body.classList.remove('light-mode', 'dark-mode');
document.body.classList.add(newTheme);
document.body.setAttribute('data-theme', newTheme === 'dark-mode' ? 'dark' : 'light');
localStorage.setItem('theme', newTheme);
document.getElementById('toggle').checked = newTheme === 'dark-mode';
return `已切换到${newTheme === 'dark-mode' ? '暗色' : '亮色'}主题`;
}
},
handleBase64: function(args) {
const base64Args = args.split(' ');
const action = base64Args[0];
const text = base64Args.slice(1).join(' ');
if (action === 'encode') {
if (!text) {
this.addAILine('请提供要编码的文本');
} else {
this.addAILine(this.utf8_to_b64(text));
}
} else if (action === 'decode') {
if (!text) {
this.addAILine('请提供要解码的Base64字符串');
} else {
try {
this.addAILine(this.b64_to_utf8(text));
} catch (e) {
this.addAILine('解码失败:无效的Base64字符串');
}
}
} else {
this.addAILine('使用方法: base64 [encode/decode] [text]');
}
},
utf8_to_b64: function(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
},
b64_to_utf8: function(str) {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
},
handleTodo: function(args) {
const todos = JSON.parse(localStorage.getItem('todos') || '[]');
const todoArgs = args.split(' ');
const action = todoArgs[0];
const text = todoArgs.slice(1).join(' ');
switch(action) {
case 'add':
if (!text) {
this.addAILine('请提供待办事项内容');
return;
}
todos.push({
id: Date.now(),
text: text,
completed: false,
date: new Date().toISOString()
});
localStorage.setItem('todos', JSON.stringify(todos));
this.addAILine(`已添加待办事项: ${text}`);
break;
case 'list':
if (todos.length === 0) {
this.addAILine('没有待办事项');
} else {
let todoList = '待办事项列表:\n';
todos.forEach((todo, index) => {
todoList += `${index + 1}. [${todo.completed ? '✓' : ' '}] ${todo.text}\n`;
});
this.addAILine(todoList);
}
break;
case 'done':
const index = parseInt(text) - 1;
if (isNaN(index) || index < 0 || index >= todos.length) {
this.addAILine('无效的待办事项编号');
return;
}
todos[index].completed = true;
localStorage.setItem('todos', JSON.stringify(todos));
this.addAILine(`已完成待办事项: ${todos[index].text}`);
break;
case 'remove':
const removeIndex = parseInt(text) - 1;
if (isNaN(removeIndex) || removeIndex < 0 || removeIndex >= todos.length) {
this.addAILine('无效的待办事项编号');
return;
}
const removedTodo = todos.splice(removeIndex, 1)[0];
localStorage.setItem('todos', JSON.stringify(todos));
this.addAILine(`已删除待办事项: ${removedTodo.text}`);
break;
default:
this.addAILine('使用方法: todo [add/list/done/remove] [内容/编号]');
}
},
showHistory: function() {
if (this.commandHistory.length === 0) {
this.addAILine('没有命令历史记录');
} else {
let historyText = '命令历史记录:\n';
this.commandHistory.slice().reverse().forEach((cmd, index) => {
historyText += `${index + 1}. ${cmd}\n`;
});
this.addAILine(historyText);
}
},
sendMessage: async function(message) {
if (!message) return;
const thinkingLine = document.createElement('div');
thinkingLine.className = 'line';
const thinkingContent = document.createElement('div');
thinkingContent.className = 'line-content ai-output';
const thinkingText = document.createElement('span');
thinkingText.textContent = '藤原: 正在思考中';
const thinkingAnimation = document.createElement('div');
thinkingAnimation.className = 'thinking-animation';
for (let i = 0; i < 3; i++) {
const dot = document.createElement('span');
thinkingAnimation.appendChild(dot);
}
thinkingContent.appendChild(thinkingText);
thinkingContent.appendChild(thinkingAnimation);
thinkingLine.appendChild(thinkingContent);
const editorContent = document.getElementById('editorContent');
if (editorContent) {
editorContent.appendChild(thinkingLine);
this.scrollToBottom();
}
try {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-a676938665e04742b75ce9e77e5e6d44'
},
body: JSON.stringify({
model: "deepseek-chat",
messages: [
{
role: "user",
content: message
}
],
temperature: 0.7
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
thinkingLine.remove();
if (data.choices && data.choices[0].message) {
const replyLine = document.createElement('div');
replyLine.className = 'line';
const replyContent = document.createElement('div');
replyContent.className = 'line-content ai-output';
replyContent.textContent = '藤原: ';
replyLine.appendChild(replyContent);
editorContent.appendChild(replyLine);
this.scrollToBottom();
await this.typeWriterEffect(replyContent, data.choices[0].message.content);
} else {
this.addAILine('无法获取AI回复,请稍后再试');
}
} catch (error) {
thinkingLine.remove();
this.addAILine(`请求失败: ${error.message}`);
}
}
};
// ==================== 页面管理器 ====================
const pageManager = {
init: function() {
this.setupNavigation();
this.titleMap = {
'home': '主页',
'terminal': '个人终端',
'tools/image-cut': '抠图工具',
'tools/audio-parse': '音频解析',
'network/ip-query': 'IP地址查询',
'media/gallery': '图片画廊',
'content/blog': '博客',
'help/faq': '常见问题',
'weather-detail': '天气详情',
'stats': '使用统计'
};
this.currentPage = 'home';
},
setupNavigation: function() {
const app = document.getElementById('app');
const toggleBtn = document.querySelector('.nav-toggle');
const navItems = document.querySelectorAll('.nav-item');
const pageTitle = document.getElementById('page-title');
// 导航栏切换
if (toggleBtn) {
toggleBtn.addEventListener('click', function () {
app.classList.toggle('open');
if (app.classList.contains('open')) {
toggleBtn.innerHTML = '<i class="fa-solid fa-xmark"></i>';
} else {
toggleBtn.innerHTML = '<i class="fa-solid fa-bars"></i>';
}
const isOpen = app.classList.contains('open');
toggleBtn.setAttribute('aria-expanded', isOpen);
toggleBtn.setAttribute('aria-label', isOpen ? '隐藏导航' : '显示导航');
});
}
// 点击内容区域关闭导航
const content = document.getElementById('content');
if (content) {
content.addEventListener('click', function (e) {
if (app.classList.contains('open') && !e.target.closest('.nav-toggle')) {
app.classList.remove('open');
if (toggleBtn) {
toggleBtn.innerHTML = '<i class="fa-solid fa-bars"></i>';
toggleBtn.setAttribute('aria-expanded', 'false');
toggleBtn.setAttribute('aria-label', '显示导航');
}
}
});
}
// 导航项点击事件
navItems.forEach(item => {
item.addEventListener('click', (e) => {
e.preventDefault();
const target = item.dataset.target;
app.classList.remove('open');
if (toggleBtn) {
toggleBtn.innerHTML = '<i class="fa-solid fa-bars"></i>';
toggleBtn.setAttribute('aria-expanded', 'false');
toggleBtn.setAttribute('aria-label', '显示导航');
}
this.loadPage(target);
});
});
// 统计按钮点击事件
const statsBtn = document.getElementById('statsBtn');
if (statsBtn) {
statsBtn.addEventListener('click', () => {
this.loadPage('stats');
});
}
},
loadPage: function(pageId) {
const mainContents = document.querySelectorAll('.main-content');
const pageFrames = document.querySelectorAll('.page-frame');
const pageTitle = document.getElementById('page-title');
// 隐藏所有内容
mainContents.forEach(content => content.style.display = 'none');
pageFrames.forEach(frame => {
frame.style.display = 'none';
frame.src = '';
});
// 记录页面访问统计
usageStats.recordFeatureUsage(pageId);
if (pageId === 'home') {
document.getElementById('home').style.display = 'block';
this.currentPage = 'home';
if (pageTitle) pageTitle.textContent = 'TENG YUAN';
return;
}
if (pageId === 'terminal') {
document.getElementById('terminal').style.display = 'block';
this.currentPage = 'terminal';
if (pageTitle) pageTitle.textContent = 'TENG YUAN - 个人终端';
return;
}
if (pageId === 'weather-detail') {
document.getElementById('weather-detail').style.display = 'block';
this.currentPage = 'weather-detail';
if (pageTitle) pageTitle.textContent = 'TENG YUAN - 天气详情';
return;
}
if (pageId === 'stats') {
document.getElementById('stats').style.display = 'block';
this.currentPage = 'stats';
if (pageTitle) pageTitle.textContent = 'TENG YUAN - 使用统计';
usageStats.renderStats();
return;
}
// 加载iframe页面
const targetFrame = document.getElementById(pageId);
if (targetFrame) {
targetFrame.src = `pages/${pageId}.html`;
targetFrame.style.display = 'block';
this.currentPage = pageId;
if (pageTitle) pageTitle.textContent = `TENG YUAN - ${this.titleMap[pageId] || pageId}`;
const currentTheme = document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
targetFrame.onload = function() {
this.contentWindow.postMessage({
type: 'THEME_CHANGE',
theme: currentTheme
}, '*');
};
}
}
};
// ==================== 搜索引擎管理器 ====================
const searchEngineManager = {
engines: {
google: {
name: 'Google',
url: 'https://www.google.com/search',
param: 'q'
},
baidu: {
name: '百度',
url: 'https://www.baidu.com/s',
param: 'wd'
},
bing: {
name: 'Bing',
url: 'https://www.bing.com/search',
param: 'q'
},
duckduckgo: {
name: 'DuckDuckGo',
url: 'https://duckduckgo.com/',
param: 'q'
}
},
init: function() {
this.currentEngine = localStorage.getItem('selectedSearchEngine') || 'google';
this.setupEventListeners();
this.updateSearchForm();
this.updateActiveButton();
},
setupEventListeners: function() {
const buttons = document.querySelectorAll('.search-engine-btn');
buttons.forEach(btn => {
btn.addEventListener('click', (e) => {
e.preventDefault();
const engine = btn.dataset.engine;
this.selectEngine(engine);
});
});
// 监听搜索表单提交
const searchForm = document.getElementById('home-search-form');
if (searchForm) {
searchForm.addEventListener('submit', (e) => {
const input = searchForm.querySelector('input[name]');
if (input && input.value.trim()) {
// 记录搜索统计
usageStats.recordSearchEngineUsage(this.currentEngine);
}
});
}
},
selectEngine: function(engine) {
this.currentEngine = engine;
localStorage.setItem('selectedSearchEngine', engine);
this.updateSearchForm();
this.updateActiveButton();
// 显示提示
this.showTooltip(`已切换到${this.engines[engine].name}搜索`);
},
updateSearchForm: function() {
const form = document.getElementById('home-search-form');
if (!form) return;
const input = form.querySelector('input[name]');
const engineConfig = this.engines[this.currentEngine];
form.action = engineConfig.url;
input.name = engineConfig.param;
},
updateActiveButton: function() {
const buttons = document.querySelectorAll('.search-engine-btn');
buttons.forEach(btn => {
btn.classList.toggle('active', btn.dataset.engine === this.currentEngine);
});
},
showTooltip: function(message) {
const tooltip = document.createElement('div');
tooltip.className = 'search-tooltip';
tooltip.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
padding: 8px 16px;
border-radius: 8px;
font-size: 0.9rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 3000;
opacity: 0;
transition: opacity 0.3s ease;
`;
tooltip.textContent = message;
document.body.appendChild(tooltip);
// 显示提示
setTimeout(() => {
tooltip.style.opacity = '1';
}, 10);
// 隐藏提示
setTimeout(() => {
tooltip.style.opacity = '0';
setTimeout(() => tooltip.remove(), 300);
}, 2000);
}
};
// ==================== 自定义网站管理器 ====================
const customSiteManager = {
init: function() {
this.setupEventListeners();
this.loadCustomSites();
},
setupEventListeners: function() {
const addSiteBtn = document.getElementById('addCustomSiteBtn');
const addSiteBtnHeader = document.getElementById('addSiteBtn');
const closeModal = document.getElementById('closeAddSiteModal');
const cancelBtn = document.getElementById('cancelAddSite');
const form = document.getElementById('addSiteForm');
[addSiteBtn, addSiteBtnHeader].forEach(btn => {
if (btn) {
btn.addEventListener('click', () => this.showAddSiteModal());
}
});
[closeModal, cancelBtn].forEach(btn => {
if (btn) {
btn.addEventListener('click', () => this.hideAddSiteModal());
}
});
if (form) {
form.addEventListener('submit', (e) => this.addSite(e));
}
// 点击模态框外部关闭
const modal = document.getElementById('addSiteModal');
if (modal) {
modal.addEventListener('click', (e) => {
if (e.target.classList.contains('modal-overlay')) {
this.hideAddSiteModal();
}
});
}
},
showAddSiteModal: function() {
const modal = document.getElementById('addSiteModal');
const siteName = document.getElementById('siteName');
if (modal) modal.classList.add('show');
if (siteName) siteName.focus();
},
hideAddSiteModal: function() {
const modal = document.getElementById('addSiteModal');
const form = document.getElementById('addSiteForm');
if (modal) modal.classList.remove('show');
if (form) form.reset();
},
addSite: function(e) {
e.preventDefault();
const name = document.getElementById('siteName').value;
const url = document.getElementById('siteUrl').value;
const desc = document.getElementById('siteDesc').value;
const icon = document.getElementById('siteIcon').value;
const site = {
id: Date.now(),
name,
url,
desc,
icon,
dateAdded: new Date().toISOString()
};
this.saveCustomSite(site);
this.renderCustomSites();
this.hideAddSiteModal();
// 显示成功消息
this.showNotification('网站添加成功!', 'success');
},
saveCustomSite: function(site) {
const sites = this.getCustomSites();
sites.push(site);
localStorage.setItem('customSites', JSON.stringify(sites));
},
getCustomSites: function() {
return JSON.parse(localStorage.getItem('customSites') || '[]');
},
deleteSite: function(siteId) {
const sites = this.getCustomSites();
const filteredSites = sites.filter(site => site.id !== siteId);
localStorage.setItem('customSites', JSON.stringify(filteredSites));
this.renderCustomSites();
this.showNotification('网站删除成功!', 'success');
},
loadCustomSites: function() {
this.renderCustomSites();
},
renderCustomSites: function() {
const container = document.getElementById('customSitesGrid');
if (!container) return;
const sites = this.getCustomSites();
if (sites.length === 0) {
container.innerHTML = `
<div class="empty-state">
<i class="fas fa-globe" style="font-size: 3rem; color: var(--startup-text-tertiary); margin-bottom: 1rem;"></i>
<h3 style="color: var(--tab-text); margin-bottom: 0.5rem;">还没有自定义网站</h3>
<p style="color: var(--startup-text-tertiary);">点击"添加网站"按钮添加您喜欢的网站</p>
</div>
`;
return;
}
container.innerHTML = sites.map(site => `
<div class="site-card custom-site-card" onclick="window.open('${site.url}', '_blank')">
<div class="site-actions">
<button class="site-action-btn edit" onclick="event.stopPropagation(); customSiteManager.editSite(${site.id})" title="编辑">
<i class="fas fa-edit"></i>
</button>
<button class="site-action-btn delete" onclick="event.stopPropagation(); customSiteManager.confirmDelete(${site.id})" title="删除">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="site-icon">
<i class="${site.icon}"></i>
</div>
<div class="site-name">${site.name}</div>
<div class="site-desc">${site.desc || '自定义网站'}</div>
</div>
`).join('');
},
confirmDelete: function(siteId) {
const site = this.getCustomSites().find(s => s.id === siteId);
if (confirm(`确定要删除"${site.name}"吗?`)) {
this.deleteSite(siteId);
}
},
showNotification: function(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'success' ? '#10b981' : '#6366f1'};
color: white;
padding: 12px 20px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 3000;
animation: slideInRight 0.3s ease;
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.style.animation = 'slideOutRight 0.3s ease';
setTimeout(() => notification.remove(), 300);
}, 3000);
}
};
// ==================== 天气详情管理器 ====================
const weatherDetailManager = {
init: function() {
this.setupEventListeners();
},
setupEventListeners: function() {
const weatherWidget = document.getElementById('weather-widget');
if (weatherWidget) {
weatherWidget.addEventListener('click', () => {
pageManager.loadPage('weather-detail');
this.loadWeatherDetail();
});
}
},
loadWeatherDetail: function() {
this.showLoading();
// 获取详细天气信息
Promise.all([
this.getCurrentWeather(),
this.getForecast()
]).then(([current, forecast]) => {
this.renderCurrentWeather(current);
this.renderForecast(forecast);
this.renderWeatherDetails(current);
}).catch(error => {
console.error('获取天气详情失败:', error);
this.showError();
});
},
getCurrentWeather: function() {
return fetch('https://api.kxzjoker.cn/api/Weather')
.then(response => response.json())
.then(data => {
if (data.code === 200 && data.data) {
return {
temp: data.data.tianqi?.temperature || '--',
condition: data.data.tianqi?.weather || '未知',
location: data.data.ipdata?.info || '未知位置',
humidity: data.data.tianqi?.humidity || '--',
wind: data.data.tianqi?.wind || '--',
pressure: data.data.tianqi?.pressure || '--',
visibility: data.data.tianqi?.visibility || '--',
aqi: data.data.tianqi?.aqi || '--'
};
}
throw new Error('无效的天气数据');
});
},
getForecast: function() {
// 模拟天气预报数据
return Promise.resolve([
{ day: '明天', temp: '25°C', condition: 'sun' },
{ day: '后天', temp: '23°C', condition: 'cloud' },
{ day: '周三', temp: '22°C', condition: 'cloud-rain' },
{ day: '周四', temp: '24°C', condition: 'cloud' },
{ day: '周五', temp: '26°C', condition: 'sun' }
]);
},
showLoading: function() {
const currentTemp = document.querySelector('.current-temp');
const currentDesc = document.querySelector('.current-desc');
const currentLocation = document.querySelector('.current-location');
const forecastList = document.getElementById('forecastList');
const weatherDetailGrid = document.getElementById('weatherDetailGrid');
if (currentTemp) currentTemp.textContent = '加载中...';
if (currentDesc) currentDesc.textContent = '获取天气信息';
if (currentLocation) currentLocation.textContent = '定位中...';
if (forecastList) forecastList.innerHTML = '<div class="loading">加载中...</div>';
if (weatherDetailGrid) weatherDetailGrid.innerHTML = '<div class="loading">加载中...</div>';
},
showError: function() {
const currentTemp = document.querySelector('.current-temp');
const currentDesc = document.querySelector('.current-desc');
const currentLocation = document.querySelector('.current-location');
const forecastList = document.getElementById('forecastList');
const weatherDetailGrid = document.getElementById('weatherDetailGrid');
if (currentTemp) currentTemp.textContent = '--°C';
if (currentDesc) currentDesc.textContent = '获取天气失败';
if (currentLocation) currentLocation.textContent = '请稍后再试';
if (forecastList) forecastList.innerHTML = '<div>无法获取天气预报</div>';
if (weatherDetailGrid) weatherDetailGrid.innerHTML = '<div>无法获取详细信息</div>';
},
renderCurrentWeather: function(data) {
const currentTemp = document.querySelector('.current-temp');
const currentDesc = document.querySelector('.current-desc');
const currentLocation = document.querySelector('.current-location');
if (currentTemp) currentTemp.textContent = `${data.temp}°C`;
if (currentDesc) currentDesc.textContent = data.condition;
if (currentLocation) currentLocation.textContent = data.location;
},
renderForecast: function(forecast) {
const forecastList = document.getElementById('forecastList');
if (!forecastList) return;
forecastList.innerHTML = forecast.map(day => `
<div class="forecast-item">
<span class="forecast-day">${day.day}</span>
<span class="forecast-icon"><i class="fas fa-${day.condition}"></i></span>
<span class="forecast-temp">${day.temp}</span>
</div>
`).join('');
},
renderWeatherDetails: function(data) {
const weatherDetailGrid = document.getElementById('weatherDetailGrid');
if (!weatherDetailGrid) return;
weatherDetailGrid.innerHTML = `
<div class="detail-item">
<div class="detail-label">湿度</div>
<div class="detail-value">${data.humidity}</div>
</div>
<div class="detail-item">
<div class="detail-label">风力</div>
<div class="detail-value">${data.wind}</div>
</div>
<div class="detail-item">
<div class="detail-label">气压</div>
<div class="detail-value">${data.pressure}</div>
</div>
<div class="detail-item">
<div class="detail-label">能见度</div>
<div class="detail-value">${data.visibility}</div>
</div>
<div class="detail-item">
<div class="detail-label">空气质量</div>
<div class="detail-value">${data.aqi}</div>
</div>
<div class="detail-item">
<div class="detail-label">日出</div>
<div class="detail-value">06:32</div>
</div>
`;
}
};
// ==================== 初始化所有功能 ====================
document.addEventListener('DOMContentLoaded', function() {
// 初始化主题
themeManager.init();
// 初始化每日一言
dailyQuote.init();
// 初始化天气
weatherWidget.init();
// 初始化主页Tab
homeTabManager.init();
// 初始化终端
terminal.init();
// 初始化页面管理器
pageManager.init();
// 初始化搜索引擎管理器
searchEngineManager.init();
// 初始化自定义网站管理器
customSiteManager.init();
// 初始化天气详情管理器
weatherDetailManager.init();
// 初始化主题编辑器
themeEditor.init();
// 初始化使用统计
usageStats.init();
// 添加动画效果
document.body.style.opacity = '0';
setTimeout(() => {
document.body.style.transition = 'opacity 0.5s ease';
document.body.style.opacity = '1';
}, 100);
});
// 添加键盘导航支持
document.addEventListener('keydown', function(e) {
// Alt+H 回到主页
if (e.altKey && e.key === 'h') {
e.preventDefault();
pageManager.loadPage('home');
}
// Alt+T 打开终端
if (e.altKey && e.key === 't') {
e.preventDefault();
pageManager.loadPage('terminal');
}
// Alt+W 打开天气详情
if (e.altKey && e.key === 'w') {
e.preventDefault();
pageManager.loadPage('weather-detail');
}
// Alt+S 打开使用统计
if (e.altKey && e.key === 's') {
e.preventDefault();
pageManager.loadPage('stats');
}
// Alt+P 打开主题编辑器
if (e.altKey && e.key === 'p') {
e.preventDefault();
themeEditor.showThemeEditor();
}
});
// 添加动画样式
const styleSheet = document.createElement('style');
styleSheet.textContent = `
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideOutRight {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(50px);
}
}
`;
document.head.appendChild(styleSheet);
</script>
</body>
</html>
index.html
style.css
index.js