<!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;
/* 自定义背景变量 */
--custom-bg-image: none;
--custom-bg-opacity: 0.3;
}
[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 1rem;
border-top-left-radius: var(--border-radius-size);
border-top-right-radius: var(--border-radius-size);
gap: 1rem;
}
/* ==================== 优化的天气和主题切换组合控件 ==================== */
.header-controls {
margin-left: auto;
display: flex;
align-items: center;
flex-shrink: 0;
}
/* 天气主题组合控件 */
.weather-theme-widget {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
border-radius: 1.25rem;
transition: all 0.3s ease;
cursor: pointer;
position: relative;
overflow: hidden;
min-width: 0;
}
body.light-mode .weather-theme-widget {
background: rgba(255, 255, 255, 0.8);
border: 1px solid rgba(229, 231, 235, 0.6);
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.05),
0 2px 4px -1px rgba(0, 0, 0, 0.03);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
body.dark-mode .weather-theme-widget {
background: rgba(30, 41, 59, 0.8);
border: 1px solid rgba(255, 255, 255, 0.15);
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(12px);
-webkit-backdrop-filter: blur(12px);
}
.weather-theme-widget:hover {
transform: translateY(-2px);
}
body.light-mode .weather-theme-widget:hover {
box-shadow: 0 8px 15px -3px rgba(0, 0, 0, 0.1);
border-color: rgba(229, 231, 235, 0.8);
}
body.dark-mode .weather-theme-widget:hover {
box-shadow: 0 8px 15px -3px rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.25);
}
/* 天气信息部分 */
.weather-section {
display: flex;
align-items: center;
gap: 0.5rem;
padding-right: 0.5rem;
border-right: 1px solid;
min-width: 0;
flex-shrink: 1;
}
body.light-mode .weather-section {
border-color: rgba(229, 231, 235, 0.6);
}
body.dark-mode .weather-section {
border-color: rgba(255, 255, 255, 0.15);
}
.weather-icon {
font-size: 1.25rem;
transition: all 0.3s ease;
flex-shrink: 0;
}
body.light-mode .weather-icon {
color: #4b5563;
}
body.dark-mode .weather-icon {
color: #f8fafc;
}
.weather-info {
display: flex;
flex-direction: column;
gap: 0.125rem;
min-width: 0;
flex-shrink: 1;
}
.weather-temp {
font-weight: 600;
font-size: 0.875rem;
transition: all 0.3s ease;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
body.light-mode .weather-temp {
color: #1f2937;
}
body.dark-mode .weather-temp {
color: #f8fafc;
}
.weather-location {
font-size: 0.625rem;
display: flex;
align-items: center;
gap: 0.125rem;
transition: all 0.3s ease;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
body.light-mode .weather-location {
color: #6b7280;
}
body.dark-mode .weather-location {
color: #94a3b8;
}
/* 主题切换部分 */
.theme-toggle-section {
display: flex;
align-items: center;
padding-left: 0.5rem;
flex-shrink: 0;
}
/* 优化的主题切换按钮 */
.theme-toggle {
position: relative;
width: 48px;
height: 24px;
cursor: pointer;
}
.theme-toggle-input {
display: none;
}
.theme-toggle-slider {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 12px;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
}
body.light-mode .theme-toggle-slider {
background: linear-gradient(135deg, #fbbf24, #f59e0b);
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.1),
0 2px 8px rgba(251, 191, 36, 0.3);
}
body.dark-mode .theme-toggle-slider {
background: linear-gradient(135deg, #1e293b, #0f172a);
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, 0.3),
0 2px 8px rgba(30, 41, 59, 0.5);
}
.theme-toggle-button {
position: absolute;
top: 2px;
width: 20px;
height: 20px;
border-radius: 50%;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.625rem;
z-index: 2;
}
body.light-mode .theme-toggle-button {
left: 2px;
background: linear-gradient(135deg, #ffffff, #f8fafc);
color: #fbbf24;
box-shadow:
0 2px 6px rgba(0, 0, 0, 0.15),
inset 0 1px 2px rgba(255, 255, 255, 0.8);
}
body.dark-mode .theme-toggle-button {
left: 26px;
background: linear-gradient(135deg, #e2e8f0, #cbd5e1);
color: #1e293b;
box-shadow:
0 2px 6px rgba(0, 0, 0, 0.2),
inset 0 1px 2px rgba(255, 255, 255, 0.3);
}
/* ==================== 集成的搜索框和搜索引擎切换 ==================== */
.search-container {
position: relative;
max-width: 600px;
margin: 0 auto;
width: 100%;
}
.integrated-search-box {
position: relative;
display: flex;
align-items: center;
background: var(--search-bg);
border: 1px solid var(--search-border);
border-radius: 28px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--tab-shadow);
transition: all 0.3s ease;
overflow: hidden;
}
.integrated-search-box:focus-within {
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);
}
/* 搜索引擎切换按钮(集成在搜索框内) */
.search-engine-toggle {
position: relative;
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
cursor: pointer;
transition: all 0.3s ease;
border-right: 1px solid var(--search-border);
min-width: 120px;
background: transparent;
border: none;
color: var(--tab-text);
}
.search-engine-toggle:hover {
background: hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.1);
}
.search-engine-icon {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
flex-shrink: 0;
}
.search-engine-name {
font-weight: 500;
font-size: 0.875rem;
white-space: nowrap;
}
.search-engine-arrow {
font-size: 0.75rem;
transition: transform 0.3s ease;
margin-left: auto;
}
.search-engine-dropdown.open .search-engine-arrow {
transform: rotate(180deg);
}
/* 搜索引擎下拉选项 */
.search-engine-options {
position: absolute;
top: 100%;
left: 0;
right: 0;
margin-top: 8px;
border-radius: 16px;
overflow: hidden;
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 9999; /* 从2000改为9999 */
}
body.light-mode .search-engine-options {
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
body.dark-mode .search-engine-options {
background: rgba(30, 41, 59, 0.95);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}
.search-engine-dropdown.open .search-engine-options {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.search-engine-option {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
cursor: pointer;
transition: all 0.2s ease;
}
body.light-mode .search-engine-option {
color: #374151;
}
body.dark-mode .search-engine-option {
color: #e2e8f0;
}
.search-engine-option:hover {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
}
.search-engine-option.active {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
font-weight: 500;
}
/* 搜索输入框 */
.search-input {
flex: 1;
height: 56px;
padding: 0 24px 0 16px;
font-size: 1rem;
border: none;
background: transparent;
color: var(--tab-text);
outline: none;
font-family: inherit;
}
.search-input::placeholder {
color: var(--startup-text-tertiary);
}
/* 搜索按钮 */
.search-submit-btn {
padding: 12px 20px;
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
border: none;
border-radius: 0 28px 28px 0;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
min-width: 56px;
}
.search-submit-btn:hover {
background: hsl(var(--primary-hue), var(--primary-saturation), calc(var(--primary-lightness) + 10%));
transform: scale(1.05);
}
/* ==================== 导航按钮样式 ==================== */
.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;
flex-shrink: 0;
}
.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);
flex-shrink: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ==================== 主界面内容 ==================== */
.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;
}
/* 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;
box-shadow: 0 4px 12px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.2);
border: 2px solid rgba(255, 255, 255, 0.1);
}
.site-card:hover .site-icon {
box-shadow: 0 8px 25px hsla(var(--primary-hue), var(--primary-saturation), var(--primary-lightness), 0.4);
border-color: rgba(255, 255, 255, 0.3);
}
.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: 600px;
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;
max-height: 90vh;
overflow-y: auto;
}
.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);
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translate(-50%, -50%) translateY(-50px) scale(0.9);
}
to {
opacity: 1;
transform: translate(-50%, -50%) translateY(0) scale(1);
}
}
/* 底部备案信息 */
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;
}
/* ==================== 响应式设计 ==================== */
@media (max-width: 768px) {
header {
padding: 0 0.75rem;
gap: 0.75rem;
}
#page-title {
font-size: 1.25rem;
}
/* 优化手机端天气主题控件 */
.weather-theme-widget {
gap: 0.375rem;
padding: 0.375rem 0.5rem;
border-radius: 1rem;
}
.weather-section {
gap: 0.375rem;
padding-right: 0.375rem;
}
.weather-icon {
font-size: 1rem;
}
.weather-temp {
font-size: 0.75rem;
}
.weather-location {
font-size: 0.5rem;
max-width: 80px;
}
.theme-toggle-section {
padding-left: 0.375rem;
}
.theme-toggle {
width: 40px;
height: 20px;
}
.theme-toggle-button {
width: 16px;
height: 16px;
font-size: 0.5rem;
}
body.light-mode .theme-toggle-button {
left: 2px;
}
body.dark-mode .theme-toggle-button {
left: 22px;
}
/* 搜索框手机端优化 */
.home-search-section {
padding: 1.5rem 1rem 0.75rem;
}
.search-engine-toggle {
min-width: 100px;
padding: 10px 12px;
}
.search-engine-name {
font-size: 0.8rem;
}
.search-input {
height: 48px;
font-size: 0.9rem;
}
.search-submit-btn {
min-width: 48px;
padding: 10px 16px;
}
.home-tabs {
flex-direction: column;
gap: 12px;
align-items: stretch;
padding: 0 1rem;
}
.tab-actions {
justify-content: center;
}
}
@media (max-width: 480px) {
header {
padding: 0 0.5rem;
gap: 0.5rem;
}
#page-title {
font-size: 1rem;
}
.weather-theme-widget {
gap: 0.25rem;
padding: 0.25rem 0.375rem;
}
.weather-section {
gap: 0.25rem;
padding-right: 0.25rem;
}
.weather-temp {
font-size: 0.625rem;
}
.weather-location {
font-size: 0.5rem;
max-width: 60px;
}
.theme-toggle {
width: 36px;
height: 18px;
}
.theme-toggle-button {
width: 14px;
height: 14px;
font-size: 0.5rem;
}
body.dark-mode .theme-toggle-button {
left: 20px;
}
}
/* ==================== 其他必要样式 ==================== */
main {
flex: 1;
padding: 0;
overflow-y: auto;
background: transparent;
-webkit-overflow-scrolling: touch;
position: relative;
}
/* 加载动画 */
@keyframes pulse {
0%, 100% {
opacity: 0.5;
}
50% {
opacity: 1;
}
}
.loading {
animation: pulse 1.5s ease-in-out infinite;
}
/* 终端样式 */
.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;
}
/* 编辑器主体 */
.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: flex;
flex-direction: column;
height: calc(100vh - 40px);
will-change: transform;
position: relative;
z-index: 5;
}
.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;
}
.close { background: var(--window-btn-close); }
.minimize {
background: var(--window-btn-minimize);
cursor: default;
opacity: 0.5;
}
.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);
}
.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%;
}
.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); }
/* 输入行 */
.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::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;
}
.background-upload-section {
margin-top: 1rem;
}
.upload-methods {
display: flex;
gap: 8px;
margin-bottom: 1rem;
}
.upload-method-btn {
flex: 1;
padding: 8px 12px;
border: 1px solid var(--card-border);
background: transparent;
color: var(--tab-text);
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 0.8rem;
}
.upload-method-btn.active {
background: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
color: white;
border-color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
}
.upload-content input[type="url"] {
width: 100%;
padding: 10px;
border: 1px solid var(--card-border);
border-radius: 8px;
background: var(--card-bg);
color: var(--tab-text);
font-size: 0.9rem;
}
.background-preview {
position: relative;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--card-border);
}
.background-preview img {
width: 100%;
height: 120px;
object-fit: cover;
}
.remove-background-btn {
position: absolute;
top: 8px;
right: 8px;
width: 24px;
height: 24px;
border: none;
background: rgba(239, 68, 68, 0.9);
color: white;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
}
.empty-state {
text-align: center;
padding: 3rem 1rem;
color: var(--startup-text-tertiary);
}
.empty-state i {
font-size: 3rem;
margin-bottom: 1rem;
opacity: 0.5;
}
.empty-state h3 {
margin-bottom: 0.5rem;
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="text-2xl font-bold" id="page-title">TENG YUAN</h1>
<!-- 优化的天气和主题切换组合控件 -->
<div class="header-controls">
<div class="weather-theme-widget" id="weather-theme-widget">
<!-- 天气信息部分 -->
<div class="weather-section" onclick="pageManager.loadPage('weather-detail')">
<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="weather-location loading" style="width: 8rem; height: 0.75rem; background: #64748b; border-radius: 0.25rem;"></span>
</div>
</div>
<!-- 主题切换部分 -->
<div class="theme-toggle-section">
<div class="theme-toggle">
<input type="checkbox" id="toggle" class="theme-toggle-input">
<label for="toggle" class="theme-toggle-slider">
<div class="theme-toggle-button">
<i class="fas fa-sun"></i>
</div>
</label>
</div>
</div>
</div>
</div>
</header>
<main>
<!-- 新主页内容 - Tab布局 -->
<div class="main-content" id="home">
<div class="home-container">
<!-- 搜索区域 -->
<div class="home-search-section">
<div class="search-container">
<!-- 集成的搜索框和搜索引擎切换 -->
<div class="search-engine-dropdown" id="searchEngineDropdown">
<div class="integrated-search-box">
<!-- 搜索引擎切换按钮(集成在搜索框内) -->
<button class="search-engine-toggle" id="searchEngineToggle">
<div class="search-engine-icon">
<i class="fab fa-google"></i>
</div>
<span class="search-engine-name">Google</span>
<i class="fas fa-chevron-down search-engine-arrow"></i>
</button>
<!-- 搜索输入框 -->
<form id="home-search-form" action="https://www.google.com/search" method="get" target="_blank" style="flex: 1; display: flex;">
<input class="search-input" type="text" name="q" placeholder="搜索互联网,发现无限可能..." autofocus>
<button type="submit" class="search-submit-btn">
<i class="fas fa-search"></i>
</button>
</form>
</div>
<!-- 搜索引擎下拉选项 -->
<div class="search-engine-options" id="searchEngineOptions">
<div class="search-engine-option active" data-engine="google">
<div class="search-engine-icon">
<i class="fab fa-google"></i>
</div>
<span class="search-engine-name">Google</span>
</div>
<div class="search-engine-option" data-engine="baidu">
<div class="search-engine-icon">
<i class="fas fa-search"></i>
</div>
<span class="search-engine-name">百度</span>
</div>
<div class="search-engine-option" data-engine="bing">
<div class="search-engine-icon">
<i class="fab fa-microsoft"></i>
</div>
<span class="search-engine-name">Bing</span>
</div>
<div class="search-engine-option" data-engine="duckduckgo">
<div class="search-engine-icon">
<i class="fas fa-duck"></i>
</div>
<span class="search-engine-name">DuckDuckGo</span>
</div>
</div>
</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 class="quick-action" onclick="window.open('https://www.bilibili.com', '_blank')">
<div class="quick-action-icon">
<i class="fas fa-play"></i>
</div>
<div class="quick-action-name">Bilibili</div>
</div>
<div class="quick-action" onclick="window.open('https://www.zhihu.com', '_blank')">
<div class="quick-action-icon">
<i class="fas fa-question"></i>
</div>
<div class="quick-action-name">知乎</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="editor" id="mainEditor" style="display: flex;">
<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>
<!-- 其他页面的iframe容器 -->
<iframe id="tools/image-cut" class="page-frame" data-title="抠图工具" style="display: none;"></iframe>
<iframe id="tools/audio-parse" class="page-frame" data-title="音频解析" style="display: none;"></iframe>
<iframe id="network/ip-query" class="page-frame" data-title="IP地址查询" style="display: none;"></iframe>
<iframe id="media/gallery" class="page-frame" data-title="图片画廊" style="display: none;"></iframe>
<iframe id="content/blog" class="page-frame" data-title="博客" style="display: none;"></iframe>
<iframe id="help/faq" class="page-frame" data-title="常见问题" style="display: none;"></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 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-control-group">
<label>自定义背景</label>
<div class="background-upload-section">
<div class="upload-methods">
<button type="button" class="upload-method-btn active" data-method="none">无背景</button>
<button type="button" class="upload-method-btn" data-method="file">本地上传</button>
<button type="button" class="upload-method-btn" data-method="url">网络链接</button>
</div>
<div class="upload-content">
<input type="file" id="backgroundFileInput" accept="image/*" style="display: none;">
<input type="url" id="backgroundUrlInput" placeholder="输入图片链接..." style="display: none;">
<div class="background-preview" id="backgroundPreview" style="display: none;">
<img id="previewImage" alt="背景预览">
<button type="button" class="remove-background-btn" id="removeBackgroundBtn">
<i class="fas fa-times"></i>
</button>
</div>
</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>
<script>
// ==================== 主题管理器 ====================
const themeManager = {
init: function() {
this.setupThemeToggle();
this.loadSavedTheme();
},
setupThemeToggle: function() {
const toggle = document.getElementById('toggle');
if (toggle) {
toggle.addEventListener('change', () => {
this.toggleTheme();
});
}
// 初始化主题状态
this.updateThemeDisplay();
},
toggleTheme: function() {
const body = document.body;
const toggle = document.getElementById('toggle');
const toggleButton = document.querySelector('.theme-toggle-button i');
if (body.classList.contains('dark-mode')) {
body.classList.remove('dark-mode');
body.classList.add('light-mode');
if (toggle) toggle.checked = false;
if (toggleButton) toggleButton.className = 'fas fa-sun';
localStorage.setItem('theme', 'light-mode');
} else {
body.classList.remove('light-mode');
body.classList.add('dark-mode');
if (toggle) toggle.checked = true;
if (toggleButton) toggleButton.className = 'fas fa-moon';
localStorage.setItem('theme', 'dark-mode');
}
// 通知iframe主题变化
this.notifyFramesThemeChange();
},
loadSavedTheme: function() {
const savedTheme = localStorage.getItem('theme') || 'light-mode';
const body = document.body;
const toggle = document.getElementById('toggle');
const toggleButton = document.querySelector('.theme-toggle-button i');
body.className = savedTheme;
if (savedTheme === 'dark-mode') {
if (toggle) toggle.checked = true;
if (toggleButton) toggleButton.className = 'fas fa-moon';
} else {
if (toggle) toggle.checked = false;
if (toggleButton) toggleButton.className = 'fas fa-sun';
}
},
updateThemeDisplay: function() {
const body = document.body;
const toggle = document.getElementById('toggle');
const toggleButton = document.querySelector('.theme-toggle-button i');
if (body.classList.contains('dark-mode')) {
if (toggle) toggle.checked = true;
if (toggleButton) toggleButton.className = 'fas fa-moon';
} else {
if (toggle) toggle.checked = false;
if (toggleButton) toggleButton.className = 'fas fa-sun';
}
},
notifyFramesThemeChange: function() {
const frames = document.querySelectorAll('.page-frame');
const currentTheme = document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
frames.forEach(frame => {
if (frame.contentWindow) {
frame.contentWindow.postMessage({
type: 'THEME_CHANGE',
theme: currentTheme
}, '*');
}
});
}
};
// ==================== 天气组件 ====================
const weatherWidget = {
init: function() {
this.loadWeatherData();
// 每30分钟更新一次天气
setInterval(() => this.loadWeatherData(), 30 * 60 * 1000);
},
loadWeatherData: function() {
// 模拟天气数据加载
setTimeout(() => {
this.updateWeatherDisplay({
temperature: '22°C',
location: '北京市',
icon: 'fas fa-sun'
});
}, 1000);
},
updateWeatherDisplay: function(data) {
const tempElement = document.querySelector('.weather-temp');
const locationElement = document.querySelector('.weather-location');
const iconElement = document.querySelector('.weather-icon i');
if (tempElement) {
tempElement.textContent = data.temperature;
tempElement.classList.remove('loading');
tempElement.style.width = 'auto';
tempElement.style.height = 'auto';
tempElement.style.background = 'transparent';
}
if (locationElement) {
locationElement.textContent = data.location;
locationElement.classList.remove('loading');
locationElement.style.width = 'auto';
locationElement.style.height = 'auto';
locationElement.style.background = 'transparent';
}
if (iconElement) {
iconElement.className = data.icon;
iconElement.parentElement.classList.remove('loading');
}
}
};
// ==================== 主页Tab管理器 ====================
const homeTabManager = {
init: function() {
this.setupTabNavigation();
this.setupQuickActions();
this.loadCustomSites();
},
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'));
button.classList.add('active');
// 更新内容显示
tabContents.forEach(content => {
content.classList.remove('active');
if (content.id === `tab-${targetTab}`) {
content.classList.add('active');
}
});
// 记录统计
if (typeof usageStats !== 'undefined') {
usageStats.recordTabUsage(targetTab);
}
});
});
},
setupQuickActions: function() {
const quickActions = document.querySelectorAll('.quick-action[data-target]');
const siteCards = document.querySelectorAll('.site-card[data-target]');
quickActions.forEach(action => {
action.addEventListener('click', () => {
const target = action.dataset.target;
if (target) {
pageManager.loadPage(target);
}
});
});
siteCards.forEach(card => {
card.addEventListener('click', () => {
const target = card.dataset.target;
if (target) {
pageManager.loadPage(target);
}
});
});
},
loadCustomSites: function() {
const customSites = JSON.parse(localStorage.getItem('customSites') || '[]');
const grid = document.getElementById('customSitesGrid');
if (grid) {
grid.innerHTML = '';
if (customSites.length === 0) {
grid.innerHTML = `
<div class="empty-state">
<i class="fas fa-bookmark"></i>
<h3>暂无自定义网站</h3>
<p>点击右上角的"+"按钮添加您喜欢的网站</p>
</div>
`;
} else {
customSites.forEach(site => {
const card = this.createSiteCard(site);
grid.appendChild(card);
});
}
}
},
createSiteCard: function(site) {
const card = document.createElement('a');
card.className = 'site-card';
card.href = site.url;
card.target = '_blank';
card.innerHTML = `
<div class="site-icon">
<img src="${site.icon || site.url + '/favicon.ico'}" alt="${site.name}"
onerror="this.innerHTML='<i class="fas fa-globe"></i>'">
</div>
<div class="site-name">${site.name}</div>
<div class="site-desc">${site.description || ''}</div>
`;
return card;
}
};
// ==================== 终端管理器 ====================
const terminal = {
init: function() {
this.setupTerminalInput();
this.updateYear();
this.commands = {
'help': this.showHelp,
'clear': this.clearTerminal,
'about': this.showAbout,
'contact': this.showContact,
'skills': this.showSkills,
'projects': this.showProjects,
'theme': this.toggleTheme,
'weather': this.showWeather,
'time': this.showTime,
'whoami': this.whoami
};
},
setupTerminalInput: function() {
const input = document.getElementById('userInput');
if (input) {
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const command = input.value.trim();
if (command) {
this.executeCommand(command);
input.value = '';
}
}
});
}
},
updateYear: function() {
const yearElement = document.getElementById('year');
if (yearElement) {
yearElement.textContent = new Date().getFullYear();
}
},
executeCommand: function(command) {
const parts = command.toLowerCase().split(' ');
const cmd = parts[0];
// 添加用户输入到终端
this.addToTerminal(`> ${command}`, 'user-input');
if (this.commands[cmd]) {
this.commands[cmd].call(this, parts.slice(1));
} else {
this.addToTerminal(`命令 '${cmd}' 未找到。输入 'help' 查看可用命令。`, 'ai-output');
}
},
addToTerminal: function(text, className = '') {
const content = document.getElementById('editorContent');
if (content) {
const line = document.createElement('div');
line.className = 'line';
line.innerHTML = `<div class="line-content ${className}">${text}</div>`;
content.appendChild(line);
// 滚动到底部
content.scrollTop = content.scrollHeight;
}
},
showHelp: function() {
const helpText = `
可用命令:
- help: 显示此帮助信息
- clear: 清空终端
- about: 关于我
- contact: 联系方式
- skills: 技能列表
- projects: 项目展示
- theme: 切换主题
- weather: 显示天气
- time: 显示当前时间
- whoami: 显示用户信息
`;
this.addToTerminal(helpText, 'ai-output');
},
clearTerminal: function() {
const content = document.getElementById('editorContent');
if (content) {
// 保留原始代码行
const originalLines = content.querySelectorAll('.line:not(.user-input):not(.ai-output)');
content.innerHTML = '';
originalLines.forEach(line => content.appendChild(line));
}
},
showAbout: function() {
this.addToTerminal('我是藤原,一名热爱技术的开发者。专注于前端开发和用户体验设计。', 'ai-output');
},
showContact: function() {
this.addToTerminal('邮箱: 2083737075@qq.com\n网站: TengYuan.icu', 'ai-output');
},
showSkills: function() {
this.addToTerminal('技能: JavaScript, HTML/CSS, React, Vue, Node.js, Python', 'ai-output');
},
showProjects: function() {
this.addToTerminal('项目: 个人网站、文件传输工具、博客系统', 'ai-output');
},
toggleTheme: function() {
themeManager.toggleTheme();
this.addToTerminal('主题已切换', 'ai-output');
},
showWeather: function() {
this.addToTerminal('当前天气: 22°C, 晴天, 北京市', 'ai-output');
},
showTime: function() {
const now = new Date();
this.addToTerminal(`当前时间: ${now.toLocaleString('zh-CN')}`, 'ai-output');
},
whoami: function() {
this.addToTerminal('当前用户: 访客 (Guest)', 'ai-output');
}
};
// ==================== 使用统计 ====================
const usageStats = {
recordPageVisit: function(pageId) {
const stats = JSON.parse(localStorage.getItem('usageStats') || '{}');
stats.pageVisits = stats.pageVisits || {};
stats.pageVisits[pageId] = (stats.pageVisits[pageId] || 0) + 1;
localStorage.setItem('usageStats', JSON.stringify(stats));
},
recordTabUsage: function(tabId) {
const stats = JSON.parse(localStorage.getItem('usageStats') || '{}');
stats.tabUsage = stats.tabUsage || {};
stats.tabUsage[tabId] = (stats.tabUsage[tabId] || 0) + 1;
localStorage.setItem('usageStats', JSON.stringify(stats));
},
recordSearchEngineUsage: function(engine) {
const stats = JSON.parse(localStorage.getItem('usageStats') || '{}');
stats.searchEngines = stats.searchEngines || {};
stats.searchEngines[engine] = (stats.searchEngines[engine] || 0) + 1;
localStorage.setItem('usageStats', JSON.stringify(stats));
}
};
// ==================== 集成的搜索引擎管理器 ====================
const searchEngineManager = {
engines: {
google: {
name: 'Google',
url: 'https://www.google.com/search',
param: 'q',
icon: 'fab fa-google'
},
baidu: {
name: '百度',
url: 'https://www.baidu.com/s',
param: 'wd',
icon: 'fas fa-search'
},
bing: {
name: 'Bing',
url: 'https://www.bing.com/search',
param: 'q',
icon: 'fab fa-microsoft'
},
duckduckgo: {
name: 'DuckDuckGo',
url: 'https://duckduckgo.com/',
param: 'q',
icon: 'fas fa-duck'
}
},
init: function() {
this.currentEngine = localStorage.getItem('selectedSearchEngine') || 'google';
this.setupEventListeners();
this.updateSearchForm();
this.updateCurrentDisplay();
},
setupEventListeners: function() {
const dropdown = document.getElementById('searchEngineDropdown');
const toggle = document.getElementById('searchEngineToggle');
const options = document.getElementById('searchEngineOptions');
const optionElements = document.querySelectorAll('.search-engine-option');
// 点击切换按钮显示/隐藏下拉菜单
toggle.addEventListener('click', (e) => {
e.stopPropagation();
dropdown.classList.toggle('open');
});
// 点击选项
optionElements.forEach(option => {
option.addEventListener('click', (e) => {
e.stopPropagation();
const engine = option.dataset.engine;
this.selectEngine(engine);
dropdown.classList.remove('open');
});
});
// 点击外部关闭下拉菜单
document.addEventListener('click', () => {
dropdown.classList.remove('open');
});
// 监听搜索表单提交
const searchForm = document.getElementById('home-search-form');
if (searchForm) {
searchForm.addEventListener('submit', (e) => {
const input = searchForm.querySelector('input[name]');
if (input && input.value.trim()) {
// 记录搜索统计
if (typeof usageStats !== 'undefined') {
usageStats.recordSearchEngineUsage(this.currentEngine);
}
}
});
}
},
selectEngine: function(engine) {
this.currentEngine = engine;
localStorage.setItem('selectedSearchEngine', engine);
this.updateSearchForm();
this.updateCurrentDisplay();
this.updateActiveOption();
// 显示提示
this.showTooltip(`已切换到${this.engines[engine].name}搜索`);
},
updateCurrentDisplay: function() {
const toggle = document.getElementById('searchEngineToggle');
const engineConfig = this.engines[this.currentEngine];
if (toggle && engineConfig) {
const icon = toggle.querySelector('.search-engine-icon i');
const name = toggle.querySelector('.search-engine-name');
if (icon) icon.className = engineConfig.icon;
if (name) name.textContent = engineConfig.name;
}
},
updateActiveOption: function() {
const options = document.querySelectorAll('.search-engine-option');
options.forEach(option => {
option.classList.toggle('active', option.dataset.engine === this.currentEngine);
});
},
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;
},
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 themeEditor = {
init: function() {
this.setupEventListeners();
this.setupBackgroundUpload(); // 添加这行
this.loadSavedTheme();
this.loadSavedBackground(); // 添加这行
},
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');
if (themeEditorBtn) themeEditorBtn.addEventListener('click', () => this.showThemeEditor());
if (closeThemeEditor) closeThemeEditor.addEventListener('click', () => this.hideThemeEditor());
if (hueSlider) hueSlider.addEventListener('input', (e) => this.updateTheme('hue', e.target.value));
if (saturationSlider) saturationSlider.addEventListener('input', (e) => this.updateTheme('saturation', e.target.value));
if (lightnessSlider) lightnessSlider.addEventListener('input', (e) => this.updateTheme('lightness', e.target.value));
if (opacitySlider) opacitySlider.addEventListener('input', (e) => this.updateTheme('opacity', e.target.value));
if (blurSlider) blurSlider.addEventListener('input', (e) => this.updateTheme('blur', e.target.value));
if (radiusSlider) radiusSlider.addEventListener('input', (e) => this.updateTheme('radius', e.target.value));
if (resetThemeBtn) resetThemeBtn.addEventListener('click', () => this.resetTheme());
if (saveThemeBtn) 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() {
const editor = document.getElementById('themeEditor');
if (editor) {
editor.classList.add('show');
this.updateValueDisplays();
}
},
hideThemeEditor: function() {
const editor = document.getElementById('themeEditor');
if (editor) {
editor.classList.remove('show');
}
},
updateTheme: function(property, value) {
const root = document.documentElement;
switch(property) {
case 'hue':
root.style.setProperty('--primary-hue', value);
const hueValue = document.getElementById('hueValue');
if (hueValue) hueValue.textContent = value + '°';
break;
case 'saturation':
root.style.setProperty('--primary-saturation', value + '%');
const saturationValue = document.getElementById('saturationValue');
if (saturationValue) saturationValue.textContent = value + '%';
break;
case 'lightness':
root.style.setProperty('--primary-lightness', value + '%');
const lightnessValue = document.getElementById('lightnessValue');
if (lightnessValue) lightnessValue.textContent = value + '%';
break;
case 'opacity':
root.style.setProperty('--background-opacity', value);
const opacityValue = document.getElementById('opacityValue');
if (opacityValue) opacityValue.textContent = Math.round(value * 100) + '%';
break;
case 'blur':
root.style.setProperty('--blur-strength', value + 'px');
const blurValue = document.getElementById('blurValue');
if (blurValue) blurValue.textContent = value + 'px';
break;
case 'radius':
root.style.setProperty('--border-radius-size', value + 'rem');
const radiusValue = document.getElementById('radiusValue');
if (radiusValue) 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();
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');
if (hueSlider) hueSlider.value = hue;
if (saturationSlider) saturationSlider.value = saturation.replace('%', '');
if (lightnessSlider) lightnessSlider.value = lightness.replace('%', '');
if (opacitySlider) opacitySlider.value = opacity;
if (blurSlider) blurSlider.value = blur.replace('px', '');
if (radiusSlider) radiusSlider.value = radius.replace('rem', '');
const hueValue = document.getElementById('hueValue');
const saturationValue = document.getElementById('saturationValue');
const lightnessValue = document.getElementById('lightnessValue');
const opacityValue = document.getElementById('opacityValue');
const blurValue = document.getElementById('blurValue');
const radiusValue = document.getElementById('radiusValue');
if (hueValue) hueValue.textContent = hue + '°';
if (saturationValue) saturationValue.textContent = saturation;
if (lightnessValue) lightnessValue.textContent = lightness;
if (opacityValue) opacityValue.textContent = Math.round(opacity * 100) + '%';
if (blurValue) blurValue.textContent = blur;
if (radiusValue) radiusValue.textContent = radius;
this.updatePresetColorSelection();
},
applyPresetColor: function() {
const hue = colorElement.dataset.hue;
const saturation = colorElement.dataset.saturation;
const lightness = colorElement.dataset.lightness;
const hueSlider = document.getElementById('hueSlider');
const saturationSlider = document.getElementById('saturationSlider');
const lightnessSlider = document.getElementById('lightnessSlider');
if (hueSlider) hueSlider.value = hue;
if (saturationSlider) saturationSlider.value = saturation;
if (lightnessSlider) lightnessSlider.value = lightness;
this.updateTheme('hue', hue);
this.updateTheme('saturation', saturation);
this.updateTheme('lightness', lightness);
this.updatePresetColorSelection();
},
updatePresetColorSelection: function() {
const hueSlider = document.getElementById('hueSlider');
const saturationSlider = document.getElementById('saturationSlider');
const lightnessSlider = document.getElementById('lightnessSlider');
if (!hueSlider || !saturationSlider || !lightnessSlider) return;
const currentHue = hueSlider.value;
const currentSaturation = saturationSlider.value;
const currentLightness = 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':
const hueSlider = document.getElementById('hueSlider');
if (hueSlider) hueSlider.value = value;
break;
case 'saturation':
const saturationSlider = document.getElementById('saturationSlider');
if (saturationSlider) saturationSlider.value = value;
break;
case 'lightness':
const lightnessSlider = document.getElementById('lightnessSlider');
if (lightnessSlider) lightnessSlider.value = value;
break;
case 'opacity':
const opacitySlider = document.getElementById('opacitySlider');
if (opacitySlider) opacitySlider.value = value;
break;
case 'blur':
const blurSlider = document.getElementById('blurSlider');
if (blurSlider) blurSlider.value = value;
break;
case 'radius':
const radiusSlider = document.getElementById('radiusSlider');
if (radiusSlider) radiusSlider.value = value;
break;
}
});
this.showNotification('主题已重置为默认设置', 'success');
},
saveTheme: function() {
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');
if (!hueSlider || !saturationSlider || !lightnessSlider || !opacitySlider || !blurSlider || !radiusSlider) return;
const theme = {
hue: hueSlider.value,
saturation: saturationSlider.value,
lightness: lightnessSlider.value,
opacity: opacitySlider.value,
blur: blurSlider.value,
radius: 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' : type === 'error' ? '#ef4444' : '#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 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': '常见问题'
};
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);
});
});
},
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 = '';
});
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 - 个人终端';
// 聚焦到输入框
setTimeout(() => {
const userInput = document.getElementById('userInput');
if (userInput) userInput.focus();
}, 100);
return;
}
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
}, '*');
};
}
// 记录页面访问统计
if (typeof usageStats !== 'undefined') {
usageStats.recordPageVisit(pageId);
}
}
};
// ==================== 初始化所有功能 ====================
document.addEventListener('DOMContentLoaded', function() {
// 初始化主题
themeManager.init();
// 初始化天气
weatherWidget.init();
// 初始化主页Tab
homeTabManager.init();
// 初始化终端
terminal.init();
// 初始化页面管理器
pageManager.init();
// 初始化搜索引擎管理器
searchEngineManager.init();
// 初始化主题编辑器
themeEditor.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');
}
});
themeEditor.setupBackgroundUpload = function() {
const methodBtns = document.querySelectorAll('.upload-method-btn');
const fileInput = document.getElementById('backgroundFileInput');
const urlInput = document.getElementById('backgroundUrlInput');
const preview = document.getElementById('backgroundPreview');
const previewImage = document.getElementById('previewImage');
const removeBtn = document.getElementById('removeBackgroundBtn');
methodBtns.forEach(btn => {
btn.addEventListener('click', () => {
methodBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const method = btn.dataset.method;
fileInput.style.display = method === 'file' ? 'block' : 'none';
urlInput.style.display = method === 'url' ? 'block' : 'none';
if (method === 'none') {
this.removeBackground();
}
});
});
if (fileInput) {
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
this.setBackground(e.target.result);
};
reader.readAsDataURL(file);
}
});
}
if (urlInput) {
urlInput.addEventListener('input', (e) => {
const url = e.target.value.trim();
if (url) {
this.setBackground(url);
}
});
}
if (removeBtn) {
removeBtn.addEventListener('click', () => {
this.removeBackground();
});
}
};
themeEditor.setBackground = function(imageUrl) {
const root = document.documentElement;
const preview = document.getElementById('backgroundPreview');
const previewImage = document.getElementById('previewImage');
root.style.setProperty('--custom-bg-image', `url(${imageUrl})`);
document.body.style.backgroundImage = `var(--custom-bg-image)`;
document.body.style.backgroundSize = 'cover';
document.body.style.backgroundPosition = 'center';
document.body.style.backgroundAttachment = 'fixed';
if (preview && previewImage) {
previewImage.src = imageUrl;
preview.style.display = 'block';
}
localStorage.setItem('customBackground', imageUrl);
};
themeEditor.removeBackground = function() {
const root = document.documentElement;
const preview = document.getElementById('backgroundPreview');
const fileInput = document.getElementById('backgroundFileInput');
const urlInput = document.getElementById('backgroundUrlInput');
root.style.setProperty('--custom-bg-image', 'none');
document.body.style.backgroundImage = '';
if (preview) preview.style.display = 'none';
if (fileInput) fileInput.value = '';
if (urlInput) urlInput.value = '';
localStorage.removeItem('customBackground');
};
themeEditor.loadSavedBackground = function() {
const savedBackground = localStorage.getItem('customBackground');
if (savedBackground) {
this.setBackground(savedBackground);
// 更新UI状态
const methodBtns = document.querySelectorAll('.upload-method-btn');
const urlInput = document.getElementById('backgroundUrlInput');
methodBtns.forEach(btn => btn.classList.remove('active'));
if (savedBackground.startsWith('data:')) {
document.querySelector('[data-method="file"]').classList.add('active');
} else {
document.querySelector('[data-method="url"]').classList.add('active');
if (urlInput) {
urlInput.value = savedBackground;
urlInput.style.display = 'block';
}
}
}
};
</script>
</body>
</html>
index.html
style.css
index.js