<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>藤原的个人终端</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Inter:wght@300;400;500;600;700&display=swap">
<style>
:root {
--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-min: #ffbd2e;
--window-btn-max: #27c93f;
--ai-output-color: #4ec9b0;
--user-input-color: #d7ba7d;
--video-bg: #000000;
--accent-color: #0a84ff;
--accent-hover: #409eff;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
--border-radius: 8px;
--calendar-today-bg: rgba(10, 132, 255, 0.3);
--calendar-selected-bg: var(--accent-color);
--weather-temp-high: #ff7e67;
--weather-temp-low: #70c1ff;
--birthday-color: #ff4081;
--birthday-bg: rgba(255, 64, 129, 0.15);
--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;
--startup-search-bg: rgba(255, 255, 255, 0.06);
--startup-search-focus: rgba(255, 255, 255, 0.1);
--startup-search-border: rgba(255, 255, 255, 0.12);
--startup-icon-bg: rgba(255, 255, 255, 0.08);
--startup-icon-hover: rgba(91, 155, 213, 0.2);
}
[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;
--video-bg: #f0f0f0;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
--calendar-today-bg: rgba(10, 132, 255, 0.2);
--weather-temp-high: #ff5a3d;
--weather-temp-low: #4a9eff;
--birthday-bg: rgba(255, 64, 129, 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;
--startup-search-bg: rgba(255, 255, 255, 0.9);
--startup-search-focus: rgba(255, 255, 255, 1);
--startup-search-border: rgba(0, 0, 0, 0.1);
--startup-icon-bg: rgba(0, 0, 0, 0.04);
--startup-icon-hover: rgba(0, 102, 204, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--editor-bg);
color: var(--text-color);
font-family: var(--font-family);
line-height: 1.6;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
transition: background-color var(--transition-normal), color var(--transition-normal);
background-image:
radial-gradient(circle at 10% 20%, rgba(100, 100, 255, 0.03) 0%, transparent 20%),
radial-gradient(circle at 90% 80%, rgba(100, 255, 100, 0.03) 0%, transparent 20%);
background-attachment: fixed;
}
/* 编辑器主体 */
.editor {
width: 100%;
max-width: 900px;
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: 80vh;
will-change: transform;
position: relative;
z-index: 100;
}
.editor:hover {
transform: translateY(-5px);
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4);
}
.editor-header {
background: var(--header-bg);
padding: 12px;
border-radius: var(--border-radius) var(--border-radius) 0 0;
display: flex;
align-items: center;
gap: 8px;
transition: background-color var(--transition-normal);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
cursor: move;
}
.window-btn {
width: 12px;
height: 12px;
border-radius: 50%;
transition: all var(--transition-fast);
position: relative;
cursor: pointer;
}
.window-btn:hover::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6px;
height: 6px;
background: rgba(0, 0, 0, 0.3);
border-radius: 50%;
}
.close { background: var(--window-btn-close); }
.minimize { background: var(--window-btn-min); }
.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;
}
.editor-content::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.editor-content::-webkit-scrollbar-track {
background: transparent;
}
.editor-content::-webkit-scrollbar-thumb {
background-color: var(--line-color);
border-radius: 4px;
}
.line {
display: flex;
padding: 2px 0;
position: relative;
min-height: 1.6em;
}
.line::before {
counter-increment: line;
content: counter(line);
color: var(--line-color);
width: 2em;
text-align: right;
padding-right: 1em;
position: absolute;
transition: color var(--transition-normal);
opacity: 0.7;
}
.line-content {
padding-left: 3em;
width: 100%;
}
.indent { margin-left: 2em; }
.indent-2 { margin-left: 4em; }
.keyword { color: var(--keyword-color); }
.string { color: var(--string-color); }
.comment { color: var(--comment-color); }
.number { color: var(--number-color); }
.function { color: var(--function-color); }
.ai-output { color: var(--ai-output-color); }
.user-input { color: var(--user-input-color); }
a {
color: var(--accent-color);
text-decoration: none;
transition: all var(--transition-fast);
position: relative;
}
a:hover {
color: var(--accent-hover);
}
a::after {
content: '';
position: absolute;
width: 0;
height: 1px;
bottom: 0;
left: 0;
background-color: var(--accent-hover);
transition: width var(--transition-normal);
}
a:hover::after {
width: 100%;
}
.cursor {
display: inline-block;
width: 2px;
height: 1.2em;
background: var(--text-color);
margin-left: 2px;
animation: blink 1s step-end infinite;
vertical-align: middle;
transition: background var(--transition-normal);
}
@keyframes blink {
50% { opacity: 0; }
}
/* 输入行 */
.input-line {
display: flex;
align-items: center;
background: var(--editor-secondary-bg);
padding: 8px 10px;
border-radius: 4px;
transition: all var(--transition-normal);
margin: 0 20px 20px;
position: sticky;
bottom: 0;
z-index: 10;
}
.input-line:focus-within {
box-shadow: 0 0 0 2px var(--accent-color);
}
.input-line::before {
content: ">";
color: var(--accent-color);
width: 2em;
text-align: right;
padding-right: 1em;
font-weight: bold;
}
.input-line input {
flex: 1;
background: transparent;
border: none;
color: var(--text-color);
font-family: var(--font-family);
font-size: 14px;
outline: none;
padding: 2px 0;
}
/* 最小化窗口样式 */
.editor.minimized {
position: fixed;
width: 300px;
height: 0px;
max-width: none;
bottom: 20px;
right: 20px;
margin: 0;
z-index: 1001;
transform: none;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
}
.editor.minimized:hover {
transform: none;
}
.editor.minimized .editor-content {
padding: 10px;
font-size: 12px;
}
.editor.minimized .input-line {
margin: 0 10px 10px;
padding: 6px 8px;
}
.editor.minimized .line-content {
padding-left: 2em;
}
.editor.minimized .line::before {
width: 1.5em;
}
/* 视频容器 */
.video-container {
margin-top: 20px;
width: 100%;
background: var(--video-bg);
border-radius: var(--border-radius);
overflow: hidden;
transition: all var(--transition-normal);
box-shadow: var(--box-shadow);
}
.video-container iframe {
width: 100%;
height: 450px;
border: none;
border-radius: var(--border-radius) var(--border-radius) 0 0;
}
.video-info {
padding: 15px;
font-size: 0.9em;
color: var(--text-color);
background: var(--editor-secondary-bg);
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.video-commands {
margin-top: 10px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.video-command {
background: var(--header-bg);
padding: 8px 16px;
border-radius: 20px;
cursor: pointer;
font-size: 0.85em;
transition: all var(--transition-fast);
border: 1px solid rgba(255, 255, 255, 0.1);
user-select: none;
}
.video-command:hover {
background: var(--accent-color);
color: white;
transform: translateY(-2px);
}
/* 图片转换器 */
.image-converter {
margin-top: 20px;
width: 100%;
background: var(--editor-secondary-bg);
border-radius: var(--border-radius);
padding: 20px;
transition: all var(--transition-normal);
box-shadow: var(--box-shadow);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.image-preview-container {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
}
.image-preview {
max-width: 100%;
max-height: 300px;
margin-bottom: 15px;
border-radius: var(--border-radius);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
transition: all var(--transition-normal);
}
.image-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 15px;
background: var(--editor-bg);
padding: 15px;
border-radius: var(--border-radius);
}
.image-control {
display: flex;
flex-direction: column;
}
.image-control label {
font-size: 0.85em;
margin-bottom: 8px;
color: var(--line-color);
}
.image-control input,
.image-control select {
background: var(--editor-secondary-bg);
border: 1px solid var(--line-color);
color: var(--text-color);
padding: 8px 12px;
border-radius: 4px;
font-family: var(--font-family);
transition: all var(--transition-fast);
}
.image-control input:focus,
.image-control select:focus {
border-color: var(--accent-color);
outline: none;
box-shadow: 0 0 0 2px rgba(10, 132, 255, 0.3);
}
.image-control input[type="range"] {
-webkit-appearance: none;
height: 6px;
background: var(--editor-bg);
border-radius: 3px;
padding: 0;
}
.image-control input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
background: var(--accent-color);
border-radius: 50%;
cursor: pointer;
}
.image-actions {
display: flex;
gap: 12px;
margin-top: 20px;
justify-content: center;
flex-wrap: wrap;
}
.image-btn {
background: var(--accent-color);
color: white;
border: none;
padding: 10px 20px;
border-radius: 20px;
cursor: pointer;
font-family: var(--font-family);
font-weight: bold;
transition: all var(--transition-fast);
min-width: 120px;
text-align: center;
}
.image-btn:hover {
background: var(--accent-hover);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(10, 132, 255, 0.3);
}
.image-download-link {
display: none;
}
/* 命令面板 */
.command-palette {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
max-width: 600px;
background: var(--editor-bg);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
z-index: 1000;
display: none;
border: 1px solid rgba(255, 255, 255, 0.1);
max-height: 70vh;
overflow: hidden;
}
.command-palette-content {
padding: 15px;
max-height: calc(70vh - 50px);
overflow-y: auto;
}
.command-search {
width: 100%;
background: var(--editor-secondary-bg);
border: 1px solid var(--line-color);
color: var(--text-color);
padding: 8px 12px;
border-radius: 4px;
font-family: var(--font-family);
margin-bottom: 15px;
}
.command-list {
max-height: 50vh;
overflow-y: auto;
}
.command-item {
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
gap: 10px;
margin: 5px 0;
transition: all var(--transition-fast);
}
.command-item:hover {
background: var(--editor-secondary-bg);
}
.command-item.selected {
background: var(--accent-color);
color: white;
}
.command-icon {
width: 16px;
height: 16px;
}
.command-shortcut {
margin-left: auto;
color: var(--line-color);
font-size: 0.8em;
background: var(--editor-secondary-bg);
padding: 2px 6px;
border-radius: 4px;
}
.command-category {
font-size: 0.8em;
color: var(--line-color);
padding: 5px 12px;
margin-top: 10px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.command-category:first-child {
border-top: none;
margin-top: 0;
}
/* 命令历史记录 */
.command-history {
margin-top: 20px;
background: var(--editor-secondary-bg);
border-radius: var(--border-radius);
padding: 15px;
display: none;
}
.history-title {
font-size: 0.9em;
margin-bottom: 10px;
color: var(--accent-color);
}
.history-list {
max-height: 200px;
overflow-y: auto;
}
.history-item {
padding: 5px 0;
cursor: pointer;
display: flex;
align-items: center;
transition: color var(--transition-fast);
}
.history-item:hover {
color: var(--accent-color);
}
.history-item::before {
content: ">";
margin-right: 10px;
color: var(--line-color);
}
/* 高级起始页样式 - 类似夸克浏览器 */
.shutdown-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--startup-bg);
background-image: var(--startup-overlay);
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
z-index: 1000;
opacity: 0;
pointer-events: none;
transition: opacity var(--transition-slow);
color: var(--startup-text);
font-family: 'Inter', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
overflow-y: auto;
padding: 0;
}
.shutdown-screen.active {
opacity: 1;
pointer-events: all;
}
.startup-container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
position: relative;
}
/* 右上角终端按钮 */
.startup-terminal-btn {
position: fixed;
top: 24px;
right: 24px;
width: 48px;
height: 48px;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: 12px;
cursor: pointer;
transition: all var(--transition-normal);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1002;
}
.startup-terminal-btn:hover {
background: var(--startup-card-hover);
transform: scale(1.05);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.startup-terminal-btn svg {
width: 20px;
height: 20px;
color: var(--startup-text-secondary);
transition: color var(--transition-normal);
}
.startup-terminal-btn:hover svg {
color: var(--startup-accent);
}
/* 顶部区域 */
.startup-header {
width: 100%;
padding: 32px 0 48px;
text-align: center;
}
.startup-logo {
font-size: 2.5rem;
font-weight: 600;
margin-bottom: 8px;
background: linear-gradient(135deg, var(--startup-accent), var(--startup-accent-hover));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: -0.02em;
}
.startup-subtitle {
font-size: 1rem;
color: var(--startup-text-secondary);
font-weight: 400;
margin-bottom: 16px;
}
.startup-time {
font-size: 0.875rem;
color: var(--startup-text-tertiary);
font-weight: 400;
padding: 8px 16px;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: 20px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
display: inline-block;
}
/* 搜索区域 */
.startup-search-section {
width: 100%;
max-width: 680px;
margin-bottom: 64px;
}
.startup-search-container {
position: relative;
width: 100%;
}
.startup-search-input {
width: 100%;
height: 56px;
padding: 0 24px 0 56px;
font-size: 1rem;
border: 1px solid var(--startup-search-border);
border-radius: 28px;
background: var(--startup-search-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
color: var(--startup-text);
transition: all var(--transition-normal);
font-family: inherit;
}
.startup-search-input::placeholder {
color: var(--startup-text-tertiary);
}
.startup-search-input:focus {
outline: none;
background: var(--startup-search-focus);
border-color: var(--startup-accent);
box-shadow: 0 0 0 3px rgba(91, 155, 213, 0.1);
}
.startup-search-icon {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
width: 20px;
height: 20px;
color: var(--startup-text-tertiary);
pointer-events: none;
}
.startup-search-engine {
position: absolute;
right: 8px;
top: 8px;
height: 40px;
display: flex;
align-items: center;
padding: 0 16px;
background: var(--startup-icon-bg);
border: 1px solid var(--startup-card-border);
border-radius: 20px;
cursor: pointer;
transition: all var(--transition-normal);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.startup-search-engine:hover {
background: var(--startup-icon-hover);
transform: scale(1.02);
}
.startup-search-engine img {
width: 18px;
height: 18px;
margin-right: 8px;
border-radius: 50%;
object-fit: contain;
}
.startup-search-engine span {
font-size: 0.875rem;
color: var(--startup-text-secondary);
font-weight: 500;
margin-right: 6px;
}
.startup-search-engine svg {
width: 12px;
height: 12px;
fill: var(--startup-text-tertiary);
}
/* 内容区域 */
.startup-content {
width: 100%;
flex: 1;
display: flex;
flex-direction: column;
gap: 32px;
margin-bottom: 48px;
}
.startup-section {
width: 100%;
}
.startup-section-title {
font-size: 1.125rem;
font-weight: 600;
color: var(--startup-text);
margin-bottom: 20px;
padding-left: 4px;
}
.startup-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
.startup-card {
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: 16px;
padding: 24px;
transition: all var(--transition-normal);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
position: relative;
overflow: hidden;
}
.startup-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, var(--startup-accent), var(--startup-accent-hover));
opacity: 0;
transition: opacity var(--transition-normal);
}
.startup-card:hover {
background: var(--startup-card-hover);
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1);
}
.startup-card:hover::before {
opacity: 1;
}
.startup-card-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.startup-card-icon {
width: 24px;
height: 24px;
margin-right: 12px;
color: var(--startup-accent);
}
.startup-card-title {
font-size: 1rem;
font-weight: 600;
color: var(--startup-text);
}
.startup-links {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
}
.startup-link {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px 12px;
background: var(--startup-icon-bg);
border: 1px solid var(--startup-card-border);
border-radius: 12px;
text-decoration: none;
color: var(--startup-text-secondary);
transition: all var(--transition-normal);
position: relative;
overflow: hidden;
}
.startup-link::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transition: left 0.6s ease;
}
.startup-link:hover::before {
left: 100%;
}
.startup-link:hover {
background: var(--startup-icon-hover);
color: var(--startup-text);
transform: translateY(-2px) scale(1.02);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
}
.startup-link-icon {
width: 40px;
height: 40px;
margin-bottom: 12px;
display: flex;
align-items: center;
justify-content: center;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: 10px;
transition: all var(--transition-normal);
}
.startup-link:hover .startup-link-icon {
background: var(--startup-accent);
border-color: var(--startup-accent);
box-shadow: 0 0 20px rgba(91, 155, 213, 0.3);
}
.startup-link-icon img {
width: 20px;
height: 20px;
object-fit: contain;
filter: brightness(1.1);
}
.startup-link:hover .startup-link-icon img {
filter: brightness(1.3);
}
.startup-link-name {
font-size: 0.875rem;
font-weight: 500;
text-align: center;
line-height: 1.3;
}
/* 思考动画 */
.thinking-animation {
display: inline-block;
position: relative;
width: 80px;
height: 20px;
}
.thinking-animation span {
position: absolute;
width: 8px;
height: 8px;
background: var(--ai-output-color);
border-radius: 50%;
animation: thinking 1.5s infinite ease-in-out;
}
.thinking-animation span:nth-child(1) {
left: 0;
animation-delay: 0s;
}
.thinking-animation span:nth-child(2) {
left: 15px;
animation-delay: 0.2s;
}
.thinking-animation span:nth-child(3) {
left: 30px;
animation-delay: 0.4s;
}
@keyframes thinking {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
body {
padding: 10px;
}
.editor {
width: 100%;
margin: 0;
font-size: 14px;
height: 90vh;
}
.editor.minimized {
width: 280px;
height: 180px;
bottom: 10px;
right: 10px;
}
.editor-content {
padding: 15px 10px;
}
.line-content {
padding-left: 2.5em;
}
.indent { margin-left: 1.5em; }
.indent-2 { margin-left: 3em; }
.title-bar {
font-size: 0.8em;
margin-left: 10px;
}
.window-btn {
width: 10px;
height: 10px;
}
.image-controls {
grid-template-columns: 1fr;
}
.command-palette {
width: 95%;
max-height: 80vh;
}
/* 起始页移动端适配 */
.startup-container {
padding: 0 16px;
}
.startup-terminal-btn {
top: 16px;
right: 16px;
width: 44px;
height: 44px;
}
.startup-terminal-btn svg {
width: 18px;
height: 18px;
}
.startup-header {
padding: 24px 0 32px;
}
.startup-logo {
font-size: 2rem;
}
.startup-subtitle {
font-size: 0.9rem;
}
.startup-search-section {
margin-bottom: 48px;
}
.startup-search-input {
height: 48px;
padding: 0 20px 0 48px;
font-size: 0.9rem;
}
.startup-search-icon {
left: 16px;
width: 18px;
height: 18px;
}
.startup-search-engine {
right: 6px;
top: 6px;
height: 36px;
padding: 0 12px;
}
.startup-search-engine span {
display: none;
}
.startup-grid {
grid-template-columns: 1fr;
gap: 16px;
}
.startup-card {
padding: 20px;
}
.startup-links {
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 10px;
}
.startup-link {
padding: 12px 8px;
}
.startup-link-icon {
width: 36px;
height: 36px;
margin-bottom: 8px;
}
.startup-link-icon img {
width: 18px;
height: 18px;
}
.startup-link-name {
font-size: 0.8rem;
}
.startup-content {
gap: 24px;
margin-bottom: 32px;
}
}
@media (max-width: 480px) {
.editor-content {
font-size: 12px;
}
.indent { margin-left: 1em; }
.indent-2 { margin-left: 2em; }
.command-palette {
max-height: 85vh;
}
.editor.minimized {
width: 260px;
height: 160px;
}
.startup-logo {
font-size: 1.75rem;
}
.startup-search-input {
height: 44px;
}
.startup-card {
padding: 16px;
}
.startup-links {
grid-template-columns: repeat(3, 1fr);
}
}
/* 滚动条优化 */
* {
scrollbar-width: thin;
scrollbar-color: var(--line-color) transparent;
}
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: var(--line-color);
border-radius: 4px;
}
*::-webkit-scrollbar-thumb:hover {
background-color: var(--accent-color);
}
/* 起始页滚动条 */
.shutdown-screen::-webkit-scrollbar {
width: 6px;
}
.shutdown-screen::-webkit-scrollbar-thumb {
background-color: var(--startup-text-tertiary);
border-radius: 3px;
}
</style>
</head>
<body>
<!-- 高级起始页 - 类似夸克浏览器 -->
<div class="shutdown-screen" id="shutdownScreen">
<!-- 右上角终端按钮 -->
<div class="startup-terminal-btn" id="startupTerminalBtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
</div>
<div class="startup-container">
<header class="startup-header">
<h1 class="startup-logo">Teng Yuan</h1>
<p class="startup-subtitle">智能终端 · 高效工作 · 极致体验</p>
<div class="startup-time" id="startupTime"></div>
</header>
<section class="startup-search-section">
<div class="startup-search-container">
<svg class="startup-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.35-4.35"></path>
</svg>
<form id="startup-search-form" action="https://www.google.com/search" method="get" target="_blank">
<input class="startup-search-input" type="text" name="q" placeholder="搜索互联网,发现无限可能..." autofocus>
<div class="startup-search-engine" id="startup-engine-selector">
<img src="https://www.google.com/favicon.ico" alt="Google" onerror="this.src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTEyIDJhMTAgMTAgMCAxIDAgMTAgMTBBMTAgMTAgMCAwIDAgMTIgMnptMCAxOGE4IDggMCAxIDEgOC04IDggOCAwIDAgMS04IDh6Ii8+PHBhdGggZD0iTTEyIDhhNCA0IDAgMSAwIDQgNCA0IDQgMCAwIDAtNC00em0wIDZhMiAyIDAgMSAxIDItMiAyIDIgMCAwIDEtMiAyeiIvPjwvc3ZnPg=='">
<span>Google</span>
<svg viewBox="0 0 16 16">
<path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
</svg>
</div>
</form>
</div>
</section>
<main class="startup-content">
<section class="startup-section">
<h2 class="startup-section-title">常用网站</h2>
<div class="startup-grid">
<div class="startup-card">
<div class="startup-card-header">
<svg class="startup-card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<polygon points="10 8 16 12 10 16 10 8"></polygon>
</svg>
<h3 class="startup-card-title">娱乐媒体</h3>
</div>
<div class="startup-links">
<a href="https://www.youtube.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.youtube.com/favicon.ico" alt="YouTube">
</div>
<div class="startup-link-name">YouTube</div>
</a>
<a href="https://www.bilibili.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.bilibili.com/favicon.ico" alt="Bilibili">
</div>
<div class="startup-link-name">Bilibili</div>
</a>
<a href="https://music.163.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://music.163.com/favicon.ico" alt="网易云音乐">
</div>
<div class="startup-link-name">网易云音乐</div>
</a>
<a href="https://www.netflix.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.netflix.com/favicon.ico" alt="Netflix">
</div>
<div class="startup-link-name">Netflix</div>
</a>
</div>
</div>
<div class="startup-card">
<div class="startup-card-header">
<svg class="startup-card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14,2 14,8 20,8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
</svg>
<h3 class="startup-card-title">开发工具</h3>
</div>
<div class="startup-links">
<a href="https://github.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://github.com/favicon.ico" alt="GitHub">
</div>
<div class="startup-link-name">GitHub</div>
</a>
<a href="https://stackoverflow.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://stackoverflow.com/favicon.ico" alt="Stack Overflow">
</div>
<div class="startup-link-name">Stack Overflow</div>
</a>
<a href="https://developer.mozilla.org" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://developer.mozilla.org/favicon.ico" alt="MDN">
</div>
<div class="startup-link-name">MDN</div>
</a>
<a href="https://v0.dev" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://v0.dev/favicon.ico" alt="v0">
</div>
<div class="startup-link-name">v0.dev</div>
</a>
</div>
</div>
</div>
</section>
<section class="startup-section">
<h2 class="startup-section-title">AI 工具</h2>
<div class="startup-grid">
<div class="startup-card">
<div class="startup-card-header">
<svg class="startup-card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
<line x1="12" y1="22.08" x2="12" y2="12"></line>
</svg>
<h3 class="startup-card-title">智能助手</h3>
</div>
<div class="startup-links">
<a href="https://chat.openai.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://chat.openai.com/favicon.ico" alt="ChatGPT">
</div>
<div class="startup-link-name">ChatGPT</div>
</a>
<a href="https://claude.ai" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://claude.ai/favicon.ico" alt="Claude">
</div>
<div class="startup-link-name">Claude</div>
</a>
<a href="https://www.midjourney.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.midjourney.com/favicon.ico" alt="Midjourney">
</div>
<div class="startup-link-name">Midjourney</div>
</a>
<a href="https://copilot.microsoft.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://copilot.microsoft.com/favicon.ico" alt="Copilot">
</div>
<div class="startup-link-name">Copilot</div>
</a>
</div>
</div>
<div class="startup-card">
<div class="startup-card-header">
<svg class="startup-card-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>
<h3 class="startup-card-title">实用工具</h3>
</div>
<div class="startup-links">
<a href="https://www.google.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.google.com/favicon.ico" alt="Google">
</div>
<div class="startup-link-name">Google</div>
</a>
<a href="https://translate.google.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://translate.google.com/favicon.ico" alt="Google 翻译">
</div>
<div class="startup-link-name">Google 翻译</div>
</a>
<a href="https://www.notion.so" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.notion.so/favicon.ico" alt="Notion">
</div>
<div class="startup-link-name">Notion</div>
</a>
<a href="https://www.figma.com" class="startup-link" target="_blank">
<div class="startup-link-icon">
<img src="https://www.figma.com/favicon.ico" alt="Figma">
</div>
<div class="startup-link-name">Figma</div>
</a>
</div>
</div>
</div>
</section>
</main>
</div>
</div>
<!-- 个人终端 -->
<div class="editor" id="mainEditor">
<div class="editor-header" id="editorHeader">
<span class="window-btn close" id="closeBtn"></span>
<span class="window-btn minimize" id="minimizeBtn"></span>
<span class="window-btn maximize" id="maximizeBtn"></span>
<span class="title-bar">terminal.js - 藤原的个人终端</span>
</div>
<div class="editor-content" id="editorContent">
<div class="line"><div class="line-content"><span class="comment">// 个人信息配置</span></div></div>
<div class="line"><div class="line-content"><span class="keyword">const</span> <span class="function">profile</span> = {</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">name</span>: <span class="string">"藤原"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">title</span>: <span class="string">"职场牛马!!!"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">contact</span>: {</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">email</span>: <span class="string"><a href="mailto:2083737075@qq.com">"2083737075@qq.com"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">website</span>: <span class="string"><a href="http://tengyuan.icu" target="_blank">"TengYuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">FileCodeBox</span>: <span class="string"><a href="http://wp.tengyuan.icu/" target="_blank">"wp.tengyuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent">},</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">links</span>: {</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">travel blog</span>: <span class="string"><a href="http://blog.tengyuan.icu/" target="_blank">"blog.tengyuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">birthday</span>: <span class="string"><a href="http://sr.0814.cn" target="_blank">"2001/11/01"</a></span>,</div></div>
<div class="line"><div class="line-content indent">},</div></div>
<div class="line"><div class="line-content indent"><span class="comment">// 座右铭</span></div></div>
<div class="line"><div class="line-content indent"><span class="keyword">motto</span>: <span class="string">"以清简代码,筑玖维数字宇宙。"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">copyright</span>: <span class="string">"2017-<span id="year"></span> 藤原"</span>,</div></div>
<div class="line"><div class="line-content">};</div></div>
<div class="line"><div class="line-content"><span class="comment">// 终端交互</span></div></div>
<div class="line"><div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"欢迎访问藤原的个人终端"</span>);</div></div>
<div class="line"><div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"输入 'help' 获取可用命令"</span>);</div></div>
<!-- 命令历史记录 -->
<div class="command-history" id="commandHistory">
<div class="history-title">命令历史记录</div>
<div class="history-list" id="historyList"></div>
</div>
</div>
<!-- 输入行 -->
<div class="input-line">
<input type="text" id="userInput" placeholder="输入命令..." autocomplete="off">
</div>
</div>
<!-- 命令面板 -->
<div class="command-palette" id="commandPalette">
<div class="editor-header">
<span class="window-btn close" id="closeCommandPaletteBtn"></span>
<span class="title-bar">command-palette.js - 命令面板</span>
</div>
<div class="command-palette-content">
<input type="text" class="command-search" id="commandSearch" placeholder="搜索命令...">
<div class="command-list" id="commandList">
<!-- 命令将通过JS动态添加 -->
</div>
</div>
</div>
<!-- 隐藏的文件输入元素 -->
<input type="file" id="fileInput" accept="image/*" style="display: none;">
<script>
// 主题切换功能
const body = document.body;
// 检查本地存储中的主题设置
const currentTheme = localStorage.getItem('theme') || 'dark';
body.setAttribute('data-theme', currentTheme);
// 主题切换函数
function switchTheme(theme) {
if (theme === 'light' || theme === '亮色') {
body.setAttribute('data-theme', 'light');
localStorage.setItem('theme', 'light');
return '已切换到亮色主题';
} else if (theme === 'dark' || theme === '暗色') {
body.setAttribute('data-theme', 'dark');
localStorage.setItem('theme', 'dark');
return '已切换到暗色主题';
} else {
// 切换主题
const currentTheme = body.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
body.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
return `已切换到${newTheme === 'dark' ? '暗色' : '亮色'}主题`;
}
}
// 设置当前年份
const currentYear = new Date().getFullYear();
document.getElementById('year').textContent = currentYear;
// 终端交互功能
const editorContent = document.getElementById('editorContent');
const userInput = document.getElementById('userInput');
const inputLine = document.querySelector('.input-line');
const fileInput = document.getElementById('fileInput');
const commandPalette = document.getElementById('commandPalette');
const commandSearch = document.getElementById('commandSearch');
const commandList = document.getElementById('commandList');
const commandHistory = document.getElementById('commandHistory');
const historyList = document.getElementById('historyList');
const closeBtn = document.getElementById('closeBtn');
const minimizeBtn = document.getElementById('minimizeBtn');
const maximizeBtn = document.getElementById('maximizeBtn');
const shutdownScreen = document.getElementById('shutdownScreen');
const startupTerminalBtn = document.getElementById('startupTerminalBtn');
const closeCommandPaletteBtn = document.getElementById('closeCommandPaletteBtn');
const mainEditor = document.getElementById('mainEditor');
const editorHeader = document.getElementById('editorHeader');
// 拖拽功能变量
let isDragging = false;
let dragOffset = { x: 0, y: 0 };
let isMinimized = false;
// 修复全屏状态下的关闭问题
closeBtn.addEventListener('click', () => {
// 如果在全屏状态,先退出全屏
if (document.fullscreenElement) {
document.exitFullscreen().then(() => {
// 退出全屏后显示起始页
setTimeout(() => {
shutdownScreen.classList.add('active');
mainEditor.style.opacity = '0';
mainEditor.style.pointerEvents = 'none';
}, 100);
}).catch(() => {
// 如果退出全屏失败,直接显示起始页
shutdownScreen.classList.add('active');
mainEditor.style.opacity = '0';
mainEditor.style.pointerEvents = 'none';
});
} else {
// 非全屏状态直接显示起始页
shutdownScreen.classList.add('active');
mainEditor.style.opacity = '0';
mainEditor.style.pointerEvents = 'none';
}
});
// 最小化功能
minimizeBtn.addEventListener('click', () => {
if (!isMinimized) {
// 最小化
mainEditor.classList.add('minimized');
isMinimized = true;
// 如果在全屏状态,先退出全屏
if (document.fullscreenElement) {
document.exitFullscreen();
}
} else {
// 恢复
mainEditor.classList.remove('minimized');
mainEditor.style.left = '';
mainEditor.style.top = '';
isMinimized = false;
}
});
maximizeBtn.addEventListener('click', () => {
if (!document.fullscreenElement && !isMinimized) {
mainEditor.requestFullscreen().catch(err => {
addAILine(`全屏模式错误: ${err.message}`);
});
} else if (document.fullscreenElement) {
document.exitFullscreen();
}
});
// 拖拽功能
editorHeader.addEventListener('mousedown', (e) => {
if (isMinimized) {
isDragging = true;
const rect = mainEditor.getBoundingClientRect();
dragOffset.x = e.clientX - rect.left;
dragOffset.y = e.clientY - rect.top;
document.addEventListener('mousemove', handleDrag);
document.addEventListener('mouseup', handleDragEnd);
e.preventDefault();
}
});
function handleDrag(e) {
if (isDragging && isMinimized) {
const x = e.clientX - dragOffset.x;
const y = e.clientY - dragOffset.y;
// 限制拖拽范围
const maxX = window.innerWidth - mainEditor.offsetWidth;
const maxY = window.innerHeight - mainEditor.offsetHeight;
const constrainedX = Math.max(0, Math.min(x, maxX));
const constrainedY = Math.max(0, Math.min(y, maxY));
mainEditor.style.left = constrainedX + 'px';
mainEditor.style.top = constrainedY + 'px';
mainEditor.style.right = 'auto';
mainEditor.style.bottom = 'auto';
}
}
function handleDragEnd() {
isDragging = false;
document.removeEventListener('mousemove', handleDrag);
document.removeEventListener('mouseup', handleDragEnd);
}
// 起始页终端按钮功能
startupTerminalBtn.addEventListener('click', () => {
shutdownScreen.classList.remove('active');
mainEditor.style.opacity = '1';
mainEditor.style.pointerEvents = 'all';
});
// 命令面板关闭按钮
closeCommandPaletteBtn.addEventListener('click', () => {
commandPalette.style.display = 'none';
userInput.focus();
});
// 命令历史记录
let commandHistoryArray = JSON.parse(localStorage.getItem('commandHistory') || '[]');
let historyIndex = -1;
// 更新命令历史记录UI
function updateHistoryUI() {
historyList.innerHTML = '';
commandHistoryArray.slice().reverse().forEach((cmd, index) => {
const item = document.createElement('div');
item.className = 'history-item';
item.textContent = cmd;
item.addEventListener('click', () => {
userInput.value = cmd;
userInput.focus();
});
historyList.appendChild(item);
});
}
// 保存命令到历史记录
function saveToHistory(command) {
if (commandHistoryArray.length === 0 || commandHistoryArray[commandHistoryArray.length - 1] !== command) {
commandHistoryArray.push(command);
if (commandHistoryArray.length > 20) {
commandHistoryArray.shift();
}
localStorage.setItem('commandHistory', JSON.stringify(commandHistoryArray));
updateHistoryUI();
}
historyIndex = -1;
}
// 可用命令列表
const commands = [
{ id: 'help', name: '帮助', description: '显示帮助信息', shortcut: '?', category: '基础' },
{ id: 'clear', name: '清空终端', description: '清除终端内容', shortcut: 'Ctrl+L', category: '基础' },
{ id: 'history', name: '命令历史', description: '显示命令历史记录', shortcut: 'H', category: '基础' },
{ id: 'theme', name: '切换主题', description: '切换深色/浅色主题', shortcut: 'T', category: '基础' },
{ id: 'video', name: '解析视频', description: '解析并播放视频', args: 'URL', category: '工具' },
{ id: 'ai', name: 'AI助手', description: '与AI助手对话', args: 'message', category: '工具' },
{ id: 'base64', name: 'Base64编解码', description: '进行Base64编码或解码', args: 'encode/decode text', category: '工具' },
{ id: 'image', name: '图片转换', description: '转换图片格式', args: 'format', category: '工具' },
{ id: 'todo', name: '待办事项', description: '管理待办事项', args: 'add/list/done/remove', category: '新功能' }
];
// 初始化命令面板
function initCommandPalette() {
commandList.innerHTML = '';
const categories = [...new Set(commands.map(cmd => cmd.category))];
categories.forEach(category => {
const categoryCommands = commands.filter(cmd => cmd.category === category);
const categoryTitle = document.createElement('div');
categoryTitle.className = 'command-category';
categoryTitle.textContent = category;
commandList.appendChild(categoryTitle);
categoryCommands.forEach(cmd => {
const item = document.createElement('div');
item.className = 'command-item';
item.dataset.id = cmd.id;
item.dataset.category = cmd.category;
const icon = document.createElement('svg');
icon.className = 'command-icon';
icon.setAttribute('width', '16');
icon.setAttribute('height', '16');
icon.setAttribute('viewBox', '0 0 24 24');
icon.setAttribute('fill', 'none');
icon.setAttribute('stroke', 'currentColor');
icon.setAttribute('stroke-width', '2');
icon.setAttribute('stroke-linecap', 'round');
icon.setAttribute('stroke-linejoin', 'round');
let iconPath;
switch(cmd.id) {
case 'help':
iconPath = '<circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line>';
break;
case 'clear':
iconPath = '<polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>';
break;
case 'video':
iconPath = '<polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect>';
break;
case 'ai':
iconPath = '<circle cx="12" cy="12" r="10"></circle><polygon points="10 8 16 12 10 16 10 8"></polygon>';
break;
case 'base64':
iconPath = '<polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline>';
break;
case 'image':
iconPath = '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline>';
break;
case 'history':
iconPath = '<circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>';
break;
case 'theme':
case '暗色':
case '亮色':
iconPath = '<circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>';
break;
case 'todo':
iconPath = '<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>';
break;
default:
iconPath = '<circle cx="12" cy="12" r="10"></circle>';
}
icon.innerHTML = iconPath;
const content = document.createElement('div');
content.style.flex = '1';
const title = document.createElement('div');
title.textContent = cmd.name;
const description = document.createElement('div');
description.textContent = cmd.description;
description.style.fontSize = '0.8em';
description.style.color = 'var(--line-color)';
content.appendChild(title);
content.appendChild(description);
const shortcut = document.createElement('div');
shortcut.className = 'command-shortcut';
shortcut.textContent = cmd.shortcut || '';
item.appendChild(icon);
item.appendChild(content);
item.appendChild(shortcut);
item.addEventListener('click', () => {
executeCommandFromPalette(cmd);
});
commandList.appendChild(item);
});
});
}
// 执行从命令面板选择的命令
function executeCommandFromPalette(cmd) {
commandPalette.style.display = 'none';
switch(cmd.id) {
case 'help':
case 'clear':
case 'history':
case 'todo':
case 'theme':
case '暗色':
case '亮色':
userInput.value = cmd.id;
break;
case 'video':
case 'ai':
case 'base64':
case 'image':
userInput.value = cmd.id + ' ';
break;
default:
return;
}
userInput.focus();
if (['help', 'clear', 'history', 'todo', 'theme', '暗色', '亮色'].includes(cmd.id)) {
const event = new KeyboardEvent('keypress', {'key': 'Enter'});
userInput.dispatchEvent(event);
}
}
// 过滤命令面板
function filterCommands(query) {
const items = commandList.querySelectorAll('.command-item');
const categories = commandList.querySelectorAll('.command-category');
query = query.toLowerCase();
let firstVisible = null;
let visibleCategories = new Set();
categories.forEach(category => {
category.style.display = 'none';
});
items.forEach(item => {
const cmd = commands.find(c => c.id === item.dataset.id);
const matchesName = cmd.name.toLowerCase().includes(query);
const matchesId = cmd.id.toLowerCase().includes(query);
const matchesDesc = cmd.description.toLowerCase().includes(query);
const matchesCategory = cmd.category.toLowerCase().includes(query);
if (matchesName || matchesId || matchesDesc || matchesCategory) {
item.style.display = 'flex';
visibleCategories.add(cmd.category);
if (!firstVisible) {
firstVisible = item;
item.classList.add('selected');
} else {
item.classList.remove('selected');
}
} else {
item.style.display = 'none';
item.classList.remove('selected');
}
});
categories.forEach(category => {
if (visibleCategories.has(category.textContent)) {
category.style.display = 'block';
}
});
if (!query) {
categories.forEach(category => {
category.style.display = 'block';
});
}
}
// 初始化键盘事件
function initKeyboardEvents() {
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'k') {
e.preventDefault();
commandPalette.style.display = 'block';
commandSearch.value = '';
filterCommands('');
commandSearch.focus();
return;
}
if (e.ctrlKey && e.key === 'l') {
e.preventDefault();
clearTerminal();
return;
}
if (e.key === 'Escape') {
commandPalette.style.display = 'none';
userInput.focus();
return;
}
if (commandPalette.style.display === 'block') {
const items = Array.from(commandList.querySelectorAll('.command-item')).filter(
item => item.style.display !== 'none'
);
if (items.length > 0) {
const currentIndex = items.findIndex(item => item.classList.contains('selected'));
if (e.key === 'ArrowDown') {
e.preventDefault();
if (currentIndex < items.length - 1) {
items[currentIndex].classList.remove('selected');
items[currentIndex + 1].classList.add('selected');
items[currentIndex + 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (currentIndex > 0) {
items[currentIndex].classList.remove('selected');
items[currentIndex - 1].classList.add('selected');
items[currentIndex - 1].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
} else if (e.key === 'Enter') {
e.preventDefault();
const selectedItem = commandList.querySelector('.command-item.selected');
if (selectedItem) {
const cmdId = selectedItem.dataset.id;
const cmd = commands.find(c => c.id === cmdId);
executeCommandFromPalette(cmd);
}
}
}
}
if (document.activeElement === userInput) {
if (e.key === 'ArrowUp' && commandHistoryArray.length > 0) {
e.preventDefault();
if (historyIndex < commandHistoryArray.length - 1) {
historyIndex++;
userInput.value = commandHistoryArray[commandHistoryArray.length - 1 - historyIndex];
}
} else if (e.key === 'ArrowDown' && historyIndex > -1) {
e.preventDefault();
historyIndex--;
if (historyIndex === -1) {
userInput.value = '';
} else {
userInput.value = commandHistoryArray[commandHistoryArray.length - 1 - historyIndex];
}
}
}
});
commandSearch.addEventListener('input', () => {
filterCommands(commandSearch.value);
});
}
// 帮助信息
const helpText = `
可用命令:
基础命令:
- help: 显示帮助信息
- clear: 清空终端
- history: 显示命令历史记录
- theme: 切换深色/浅色主题
- 暗色: 切换到暗色主题
- 亮色: 切换到亮色主题
工具命令:
- video [url]: 解析并播放视频
例如: video https://v.qq.com/x/cover/mzc00200mp8er9d.html
- ai [message]: 与AI助手对话
例如: ai 你好
- base64 [encode/decode] [text]: 进行Base64编码/解码
例如: base64 encode 你好世界
- image [format]: 转换图片格式 (支持: jpg, png, webp, bmp)
例如: image png
新功能:
- todo [add/list/done/remove]: 管理待办事项
例如: todo add 完成项目报告
快捷键:
- Ctrl+K: 打开命令面板
- Ctrl+L: 清空终端
- 上/下箭头: 浏览命令历史
`;
// 打字机效果函数
function typeWriterEffect(element, text, speed = 10) {
return new Promise((resolve) => {
let i = 0;
const typing = () => {
if (i < text.length) {
element.textContent += text.charAt(i);
i++;
setTimeout(typing, speed);
} else {
const cursor = element.querySelector('.cursor');
if (cursor) cursor.remove();
resolve();
}
};
const cursorSpan = document.createElement('span');
cursorSpan.className = 'cursor';
element.appendChild(cursorSpan);
typing();
});
}
async function addAILine(text) {
const line = document.createElement('div');
line.className = 'line';
const lineContent = document.createElement('div');
lineContent.className = 'line-content ai-output';
lineContent.textContent = '藤原: ';
line.appendChild(lineContent);
editorContent.appendChild(line);
editorContent.scrollTop = editorContent.scrollHeight;
await typeWriterEffect(lineContent, text);
return line;
}
function addUserLine(text) {
const line = document.createElement('div');
line.className = 'line';
const lineContent = document.createElement('div');
lineContent.className = 'line-content user-input';
lineContent.textContent = `> ${text}`;
line.appendChild(lineContent);
editorContent.appendChild(line);
editorContent.scrollTop = editorContent.scrollHeight;
return line;
}
// 清除终端内容函数
function clearTerminal() {
const lines = document.querySelectorAll('.line');
const commandHistoryElem = document.getElementById('commandHistory');
const imageConverter = document.querySelector('.image-converter');
const videoContainer = document.querySelector('.video-container');
lines.forEach(line => {
if (!line.classList.contains('input-line')) {
line.remove();
}
});
if (commandHistoryElem) commandHistoryElem.style.display = 'none';
if (imageConverter) imageConverter.remove();
if (videoContainer) videoContainer.remove();
}
// 创建视频播放器
function createVideoPlayer(videoUrl) {
const existingPlayer = document.querySelector('.video-container');
if (existingPlayer) {
existingPlayer.remove();
}
const videoContainer = document.createElement('div');
videoContainer.className = 'video-container';
const iframe = document.createElement('iframe');
iframe.src = videoUrl;
iframe.style.width = '100%';
iframe.style.height = '450px';
iframe.style.border = 'none';
iframe.style.borderRadius = '8px 8px 0 0';
const videoInfo = document.createElement('div');
videoInfo.className = 'video-info';
videoInfo.textContent = '视频播放器';
const videoCommands = document.createElement('div');
videoCommands.className = 'video-commands';
const closeBtn = document.createElement('div');
closeBtn.className = 'video-command';
closeBtn.textContent = '关闭视频';
closeBtn.addEventListener('click', () => {
videoContainer.remove();
});
videoCommands.appendChild(closeBtn);
videoContainer.appendChild(iframe);
videoContainer.appendChild(videoInfo);
videoContainer.appendChild(videoCommands);
editorContent.appendChild(videoContainer);
editorContent.scrollTop = editorContent.scrollHeight;
}
// 解析视频
async function parseVideo(url) {
try {
if (!/^https?:\/\/.+/.test(url)) {
addAILine('错误:请提供有效的URL地址');
return;
}
const loadingLine = await addAILine('正在解析视频,请稍候...');
const apiUrl = `https://www.yemu.xyz/?url=${encodeURIComponent(url)}`;
createVideoPlayer(apiUrl);
loadingLine.querySelector('.line-content').textContent = '藤原: 视频已加载,如果无法播放,请尝试其他解析接口';
} catch (error) {
addAILine(`视频解析失败: ${error.message}`);
}
}
// 创建图片转换器界面
function createImageConverter(targetFormat) {
const existingConverter = document.querySelector('.image-converter');
if (existingConverter) {
existingConverter.remove();
}
const converter = document.createElement('div');
converter.className = 'image-converter';
const previewContainer = document.createElement('div');
previewContainer.className = 'image-preview-container';
const previewText = document.createElement('div');
previewText.textContent = '请选择要转换的图片';
previewText.className = 'ai-output';
const previewImage = document.createElement('img');
previewImage.className = 'image-preview';
previewImage.style.display = 'none';
previewContainer.appendChild(previewText);
previewContainer.appendChild(previewImage);
const controls = document.createElement('div');
controls.className = 'image-controls';
// 图片质量控制
const qualityControl = document.createElement('div');
qualityControl.className = 'image-control';
const qualityLabel = document.createElement('label');
qualityLabel.textContent = '图片质量 (0-100)';
qualityLabel.htmlFor = 'imageQuality';
const qualityInput = document.createElement('input');
qualityInput.type = 'range';
qualityInput.id = 'imageQuality';
qualityInput.min = '0';
qualityInput.max = '100';
qualityInput.value = '80';
const qualityValue = document.createElement('span');
qualityValue.textContent = '80';
qualityValue.style.marginLeft = '5px';
qualityValue.style.fontSize = '0.8em';
qualityInput.addEventListener('input', () => {
qualityValue.textContent = qualityInput.value;
});
qualityControl.appendChild(qualityLabel);
qualityControl.appendChild(qualityInput);
qualityControl.appendChild(qualityValue);
// 图片格式选择
const formatControl = document.createElement('div');
formatControl.className = 'image-control';
const formatLabel = document.createElement('label');
formatLabel.textContent = '目标格式';
formatLabel.htmlFor = 'imageFormat';
const formatSelect = document.createElement('select');
formatSelect.id = 'imageFormat';
const formats = ['jpg', 'jpeg', 'png', 'webp', 'bmp'];
formats.forEach(format => {
const option = document.createElement('option');
option.value = format;
option.textContent = format.toUpperCase();
if (format === targetFormat) option.selected = true;
formatSelect.appendChild(option);
});
formatControl.appendChild(formatLabel);
formatControl.appendChild(formatSelect);
controls.appendChild(qualityControl);
controls.appendChild(formatControl);
// 操作按钮
const actions = document.createElement('div');
actions.className = 'image-actions';
const selectBtn = document.createElement('button');
selectBtn.className = 'image-btn';
selectBtn.textContent = '选择图片';
selectBtn.addEventListener('click', () => {
fileInput.click();
});
const convertBtn = document.createElement('button');
convertBtn.className = 'image-btn';
convertBtn.textContent = '转换图片';
convertBtn.addEventListener('click', () => {
if (!previewImage.src) {
addAILine('请先选择要转换的图片');
return;
}
convertImage(previewImage, formatSelect.value, qualityInput.value);
});
const downloadBtn = document.createElement('button');
downloadBtn.className = 'image-btn';
downloadBtn.textContent = '下载图片';
downloadBtn.style.display = 'none';
downloadBtn.id = 'downloadBtn';
const downloadLink = document.createElement('a');
downloadLink.className = 'image-download-link';
downloadLink.id = 'downloadLink';
downloadLink.download = `converted-image.${formatSelect.value}`;
actions.appendChild(selectBtn);
actions.appendChild(convertBtn);
actions.appendChild(downloadBtn);
actions.appendChild(downloadLink);
converter.appendChild(previewContainer);
converter.appendChild(controls);
converter.appendChild(actions);
editorContent.appendChild(converter);
editorContent.scrollTop = editorContent.scrollHeight;
// 文件选择处理
fileInput.onchange = (e) => {
const file = e.target.files[0];
if (!file) return;
if (!file.type.match('image.*')) {
addAILine('请选择有效的图片文件');
return;
}
const reader = new FileReader();
reader.onload = (event) => {
previewImage.src = event.target.result;
previewImage.style.display = 'block';
previewText.textContent = '预览:';
previewText.className = 'ai-output';
};
reader.readAsDataURL(file);
};
}
// 转换图片
function convertImage(imgElement, format, quality) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = imgElement.naturalWidth;
canvas.height = imgElement.naturalHeight;
ctx.drawImage(imgElement, 0, 0);
let mimeType;
switch (format.toLowerCase()) {
case 'jpg':
case 'jpeg':
mimeType = 'image/jpeg';
break;
case 'png':
mimeType = 'image/png';
break;
case 'webp':
mimeType = 'image/webp';
break;
case 'bmp':
mimeType = 'image/bmp';
break;
default:
mimeType = 'image/jpeg';
}
let qualityValue = parseInt(quality) / 100;
if (isNaN(qualityValue)) qualityValue = 0.8;
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const downloadLink = document.getElementById('downloadLink');
const downloadBtn = document.getElementById('downloadBtn');
if (downloadLink && downloadBtn) {
downloadLink.href = url;
downloadLink.download = `converted-image.${format}`;
downloadBtn.style.display = 'inline-block';
downloadBtn.onclick = () => {
downloadLink.click();
addAILine(`图片已转换完成!`);
};
}
const previewImage = document.querySelector('.image-preview');
if (previewImage) {
previewImage.src = url;
}
addAILine(`图片已成功转换为 ${format.toUpperCase()} 格式!点击"下载图片"按钮保存结果。`);
}, mimeType, qualityValue);
}
// 显示命令历史
function toggleCommandHistory() {
if (commandHistory.style.display === 'none' || !commandHistory.style.display) {
commandHistory.style.display = 'block';
updateHistoryUI();
} else {
commandHistory.style.display = 'none';
}
}
// 待办事项功能
function manageTodo(action, text) {
const todos = JSON.parse(localStorage.getItem('todos') || '[]');
switch(action) {
case 'add':
if (!text) {
addAILine('请提供待办事项内容');
return;
}
todos.push({
id: Date.now(),
text: text,
completed: false,
date: new Date().toISOString()
});
localStorage.setItem('todos', JSON.stringify(todos));
addAILine(`已添加待办事项: ${text}`);
break;
case 'list':
if (todos.length === 0) {
addAILine('没有待办事项');
} else {
let todoList = '待办事项列表:\n';
todos.forEach((todo, index) => {
todoList += `${index + 1}. [${todo.completed ? '✓' : ' '}] ${todo.text}\n`;
});
addAILine(todoList);
}
break;
case 'done':
const index = parseInt(text) - 1;
if (isNaN(index) || index < 0 || index >= todos.length) {
addAILine('无效的待办事项编号');
return;
}
todos[index].completed = true;
localStorage.setItem('todos', JSON.stringify(todos));
addAILine(`已完成待办事项: ${todos[index].text}`);
break;
case 'remove':
const removeIndex = parseInt(text) - 1;
if (isNaN(removeIndex) || removeIndex < 0 || removeIndex >= todos.length) {
addAILine('无效的待办事项编号');
return;
}
const removedTodo = todos.splice(removeIndex, 1)[0];
localStorage.setItem('todos', JSON.stringify(todos));
addAILine(`已删除待办事项: ${removedTodo.text}`);
break;
default:
addAILine('使用方法: todo [add/list/done/remove] [内容/编号]');
}
}
// Base64编码函数
function utf8_to_b64(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
// Base64解码函数
function b64_to_utf8(str) {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
async function sendMessage(message) {
if (!message) return;
addUserLine(message);
const thinkingLine = document.createElement('div');
thinkingLine.className = 'line';
const thinkingContent = document.createElement('div');
thinkingContent.className = 'line-content ai-output';
const thinkingText = document.createElement('span');
thinkingText.textContent = '藤原: 正在思考中 ';
const thinkingAnimation = document.createElement('div');
thinkingAnimation.className = 'thinking-animation';
for (let i = 0; i < 3; i++) {
const dot = document.createElement('span');
thinkingAnimation.appendChild(dot);
}
thinkingContent.appendChild(thinkingText);
thinkingContent.appendChild(thinkingAnimation);
thinkingLine.appendChild(thinkingContent);
editorContent.appendChild(thinkingLine);
editorContent.scrollTop = editorContent.scrollHeight;
try {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-a676938665e04742b75ce9e77e5e6d44'
},
body: JSON.stringify({
model: "deepseek-chat",
messages: [
{
role: "user",
content: message
}
],
temperature: 0.7
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
thinkingLine.remove();
if (data.choices && data.choices[0].message) {
const replyLine = document.createElement('div');
replyLine.className = 'line';
const replyContent = document.createElement('div');
replyContent.className = 'line-content ai-output';
replyContent.textContent = '藤原: ';
replyLine.appendChild(replyContent);
editorContent.appendChild(replyLine);
editorContent.scrollTop = editorContent.scrollHeight;
await typeWriterEffect(replyContent, data.choices[0].message.content);
} else {
addAILine('无法获取AI回复,请稍后再试');
}
} catch (error) {
thinkingLine.remove();
const errorLine = document.createElement('div');
errorLine.className = 'line';
const errorContent = document.createElement('div');
errorContent.className = 'line-content ai-output';
errorContent.textContent = `藤原: 请求失败: ${error.message}`;
errorLine.appendChild(errorContent);
editorContent.appendChild(errorLine);
editorContent.scrollTop = editorContent.scrollHeight;
}
}
// 处理用户命令
function processCommand(command) {
const parts = command.split(' ');
const cmd = parts[0].toLowerCase();
const args = parts.slice(1).join(' ');
saveToHistory(command);
switch(cmd) {
case 'help':
addAILine(helpText);
break;
case 'clear':
clearTerminal();
break;
case 'video':
if (!args) {
addAILine('请提供视频URL,例如: video https://v.qq.com/x/cover/mzc00200mp8er9d.html');
} else {
parseVideo(args);
}
break;
case 'ai':
if (!args) {
addAILine('请输入您想对AI说的话');
} else {
sendMessage(args);
}
break;
case 'base64':
const base64Args = args.split(' ');
const action = base64Args[0];
const text = base64Args.slice(1).join(' ');
if (action === 'encode') {
if (!text) {
addAILine('请提供要编码的文本');
} else {
addAILine(utf8_to_b64(text));
}
} else if (action === 'decode') {
if (!text) {
addAILine('请提供要解码的Base64字符串');
} else {
try {
addAILine(b64_to_utf8(text));
} catch (e) {
addAILine('解码失败:无效的Base64字符串');
}
}
} else {
addAILine('使用方法: base64 [encode/decode] [text]');
}
break;
case 'image':
if (!args) {
addAILine('请指定目标图片格式,例如: image png');
} else {
const validFormats = ['jpg', 'jpeg', 'png', 'webp', 'bmp'];
if (validFormats.includes(args.toLowerCase())) {
createImageConverter(args.toLowerCase());
} else {
addAILine(`不支持的目标格式: ${args}。支持格式: ${validFormats.join(', ')}`);
}
}
break;
case 'history':
toggleCommandHistory();
break;
case 'theme':
addAILine(switchTheme());
break;
case '暗色':
addAILine(switchTheme('暗色'));
break;
case '亮色':
addAILine(switchTheme('亮色'));
break;
case 'todo':
const todoArgs = args.split(' ');
const todoAction = todoArgs[0];
const todoText = todoArgs.slice(1).join(' ');
manageTodo(todoAction, todoText);
break;
default:
if (command.startsWith('http://') || command.startsWith('https://')) {
parseVideo(command);
} else if (command) {
sendMessage(command);
}
}
}
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const command = userInput.value.trim();
if (command) {
processCommand(command);
userInput.value = '';
}
}
});
// 搜索引擎配置
const searchEngines = {
google: {
name: "Google",
url: "https://www.google.com/search",
param: "q",
icon: "https://www.google.com/favicon.ico"
},
baidu: {
name: "百度",
url: "https://www.baidu.com/s",
param: "wd",
icon: "https://www.baidu.com/favicon.ico"
},
bing: {
name: "Bing",
url: "https://www.bing.com/search",
param: "q",
icon: "https://www.bing.com/favicon.ico"
}
};
let currentEngine = 'google';
// 更新实时时间
function updateTime() {
const now = new Date();
const options = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
};
const timeString = now.toLocaleDateString('zh-CN', options);
// 更新起始页时间
const startupTimeElement = document.getElementById('startupTime');
if (startupTimeElement) {
startupTimeElement.textContent = timeString;
}
}
updateTime();
setInterval(updateTime, 1000);
// 切换搜索引擎
function setSearchEngine(engine) {
if (searchEngines[engine]) {
currentEngine = engine;
const searchForm = document.getElementById('startup-search-form');
if (searchForm) {
searchForm.action = searchEngines[engine].url;
searchForm.querySelector('input[name="q"]').name = searchEngines[engine].param;
const img = document.querySelector('#startup-engine-selector img');
const span = document.querySelector('#startup-engine-selector span');
if (img && span) {
img.src = searchEngines[engine].icon;
img.alt = searchEngines[engine].name;
span.textContent = searchEngines[engine].name;
}
}
}
}
setSearchEngine(currentEngine);
// 初始化
initCommandPalette();
initKeyboardEvents();
updateHistoryUI();
userInput.focus();
setTimeout(() => {
addAILine('欢迎来到藤原的个人终端!输入 "help" 获取可用命令。');
}, 500);
</script>
</body>
</html>
index.html
style.css
index.js