3083 lines
104 KiB
HTML
3083 lines
104 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>CyberOS - 赛博朋克操作系统</title>
|
|
|
|
<!-- 引入第三方依赖 -->
|
|
<!-- Font Awesome 图标库 -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<!-- Google Fonts - 科技感字体 -->
|
|
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Roboto:wght@300;400;500;700&family=Share+Tech+Mono&display=swap" rel="stylesheet">
|
|
<!-- Chart.js - 数据可视化 -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
|
|
<!-- Anime.js - 动画库 -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
|
|
|
|
<style>
|
|
/* ==================== CSS 变量定义 ==================== */
|
|
:root {
|
|
/* 赛博朋克霓虹配色 */
|
|
--neon-pink: #ff00ff;
|
|
--neon-purple: #bf00ff;
|
|
--neon-cyan: #00ffff;
|
|
--neon-blue: #0066ff;
|
|
--neon-green: #00ff88;
|
|
--neon-yellow: #ffee00;
|
|
--neon-orange: #ff6600;
|
|
--neon-red: #ff0044;
|
|
|
|
/* 背景色 */
|
|
--bg-dark: #0a0a0f;
|
|
--bg-darker: #050508;
|
|
--bg-card: rgba(20, 20, 35, 0.9);
|
|
|
|
/* 玻璃效果 */
|
|
--glass-bg: rgba(20, 20, 35, 0.85);
|
|
--glass-border: rgba(255, 255, 255, 0.1);
|
|
--glass-blur: 20px;
|
|
|
|
/* 文字颜色 */
|
|
--text-primary: #ffffff;
|
|
--text-secondary: rgba(255, 255, 255, 0.7);
|
|
--text-muted: rgba(255, 255, 255, 0.4);
|
|
|
|
/* 字体 */
|
|
--font-display: 'Orbitron', sans-serif;
|
|
--font-body: 'Roboto', sans-serif;
|
|
--font-mono: 'Share Tech Mono', monospace;
|
|
|
|
/* 阴影 */
|
|
--shadow-glow: 0 0 20px var(--neon-cyan);
|
|
--shadow-pink: 0 0 20px var(--neon-pink);
|
|
}
|
|
|
|
/* ==================== 全局样式 ==================== */
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html, body {
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
font-family: var(--font-body);
|
|
background: var(--bg-dark);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
/* 滚动条样式 */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: var(--bg-dark);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--neon-purple);
|
|
border-radius: 4px;
|
|
}
|
|
|
|
/* ==================== 启动动画 ==================== */
|
|
#boot-screen {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: var(--bg-darker);
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 100000;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.boot-logo {
|
|
font-family: var(--font-display);
|
|
font-size: 4rem;
|
|
font-weight: 900;
|
|
color: var(--neon-cyan);
|
|
text-shadow: 0 0 30px var(--neon-cyan), 0 0 60px var(--neon-purple);
|
|
margin-bottom: 2rem;
|
|
letter-spacing: 0.5rem;
|
|
}
|
|
|
|
.boot-loader {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.boot-loader span {
|
|
width: 12px;
|
|
height: 12px;
|
|
background: var(--neon-pink);
|
|
border-radius: 50%;
|
|
animation: bootPulse 1s ease-in-out infinite;
|
|
}
|
|
|
|
.boot-loader span:nth-child(2) { animation-delay: 0.2s; }
|
|
.boot-loader span:nth-child(3) { animation-delay: 0.4s; }
|
|
.boot-loader span:nth-child(4) { animation-delay: 0.6s; }
|
|
.boot-loader span:nth-child(5) { animation-delay: 0.8s; }
|
|
|
|
@keyframes bootPulse {
|
|
0%, 100% { transform: scale(1); opacity: 1; }
|
|
50% { transform: scale(1.5); opacity: 0.5; }
|
|
}
|
|
|
|
.boot-text {
|
|
font-family: var(--font-mono);
|
|
color: var(--text-secondary);
|
|
margin-top: 2rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* ==================== 锁屏界面 ==================== */
|
|
#lock-screen {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(135deg, var(--bg-darker) 0%, #1a0a2e 50%, #0a0a1a 100%);
|
|
display: none;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 99999;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#lock-screen.active {
|
|
display: flex;
|
|
}
|
|
|
|
.lock-time {
|
|
font-family: var(--font-display);
|
|
font-size: 5rem;
|
|
color: var(--text-primary);
|
|
text-shadow: 0 0 30px var(--neon-cyan);
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.lock-date {
|
|
font-family: var(--font-mono);
|
|
font-size: 1.5rem;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.lock-avatar {
|
|
width: 100px;
|
|
height: 100px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple));
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-size: 3rem;
|
|
margin-bottom: 1rem;
|
|
box-shadow: 0 0 30px var(--neon-pink);
|
|
}
|
|
|
|
.lock-username {
|
|
font-size: 1.2rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.lock-password {
|
|
width: 300px;
|
|
padding: 1rem;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
color: var(--text-primary);
|
|
font-family: var(--font-mono);
|
|
text-align: center;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.lock-password::placeholder {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.lock-password:focus {
|
|
outline: none;
|
|
border-color: var(--neon-cyan);
|
|
box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
|
|
}
|
|
|
|
.lock-hint {
|
|
margin-top: 1rem;
|
|
font-size: 0.8rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* ==================== 桌面背景 ==================== */
|
|
#desktop {
|
|
width: 100%;
|
|
height: calc(100% - 60px);
|
|
position: relative;
|
|
overflow: hidden;
|
|
background: var(--bg-dark);
|
|
}
|
|
|
|
.desktop-bg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background:
|
|
radial-gradient(ellipse at 20% 80%, rgba(191, 0, 255, 0.15) 0%, transparent 50%),
|
|
radial-gradient(ellipse at 80% 20%, rgba(0, 255, 255, 0.15) 0%, transparent 50%),
|
|
radial-gradient(ellipse at 50% 50%, rgba(0, 102, 255, 0.1) 0%, transparent 70%),
|
|
linear-gradient(180deg, var(--bg-darker) 0%, var(--bg-dark) 100%);
|
|
z-index: 0;
|
|
}
|
|
|
|
/* 网格效果 */
|
|
.grid-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image:
|
|
linear-gradient(rgba(0, 255, 255, 0.03) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(0, 255, 255, 0.03) 1px, transparent 1px);
|
|
background-size: 50px 50px;
|
|
pointer-events: none;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* 扫描线效果 */
|
|
.scanlines {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: repeating-linear-gradient(
|
|
0deg,
|
|
transparent,
|
|
transparent 2px,
|
|
rgba(0, 0, 0, 0.1) 2px,
|
|
rgba(0, 0, 0, 0.1) 4px
|
|
);
|
|
pointer-events: none;
|
|
z-index: 2;
|
|
}
|
|
|
|
/* ==================== 桌面图标 ==================== */
|
|
.desktop-icons {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
z-index: 10;
|
|
}
|
|
|
|
.desktop-icon {
|
|
width: 80px;
|
|
padding: 0.8rem 0.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
border: 1px solid transparent;
|
|
}
|
|
|
|
.desktop-icon:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-color: var(--neon-cyan);
|
|
box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
|
|
}
|
|
|
|
.desktop-icon .icon {
|
|
font-size: 2.5rem;
|
|
color: var(--neon-cyan);
|
|
text-shadow: 0 0 10px var(--neon-cyan);
|
|
}
|
|
|
|
.desktop-icon span {
|
|
font-size: 0.75rem;
|
|
text-align: center;
|
|
color: var(--text-primary);
|
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
|
|
}
|
|
|
|
/* ==================== 桌面小部件 ==================== */
|
|
.desktop-widgets {
|
|
position: absolute;
|
|
top: 20px;
|
|
right: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
z-index: 10;
|
|
}
|
|
|
|
.widget {
|
|
width: 200px;
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(var(--glass-blur));
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 12px;
|
|
padding: 1rem;
|
|
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.widget-clock {
|
|
text-align: center;
|
|
}
|
|
|
|
.widget-clock .time {
|
|
font-family: var(--font-display);
|
|
font-size: 2rem;
|
|
color: var(--neon-cyan);
|
|
text-shadow: 0 0 10px var(--neon-cyan);
|
|
}
|
|
|
|
.widget-clock .date {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.widget-calendar {
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.widget-calendar .month {
|
|
color: var(--neon-pink);
|
|
font-size: 0.9rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.widget-calendar .day {
|
|
font-family: var(--font-display);
|
|
font-size: 3rem;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
/* ==================== 窗口系统 ==================== */
|
|
#windows-container {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 100;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.window {
|
|
position: absolute;
|
|
min-width: 400px;
|
|
min-height: 300px;
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(var(--glass-blur));
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 12px;
|
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
flex-direction: column;
|
|
pointer-events: all;
|
|
overflow: hidden;
|
|
transition: box-shadow 0.3s ease;
|
|
}
|
|
|
|
.window.active {
|
|
z-index: 1000;
|
|
box-shadow: 0 0 40px rgba(191, 0, 255, 0.3);
|
|
}
|
|
|
|
.window.inactive {
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.window-header {
|
|
height: 40px;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 1rem;
|
|
cursor: move;
|
|
border-bottom: 1px solid var(--glass-border);
|
|
}
|
|
|
|
.window-icon {
|
|
color: var(--neon-cyan);
|
|
margin-right: 0.5rem;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.window-title {
|
|
flex: 1;
|
|
font-family: var(--font-mono);
|
|
font-size: 0.85rem;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.window-controls {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.window-btn {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 50%;
|
|
border: none;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 0.7rem;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.window-btn.minimize {
|
|
background: rgba(255, 193, 7, 0.8);
|
|
color: #000;
|
|
}
|
|
|
|
.window-btn.maximize {
|
|
background: rgba(76, 175, 80, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.window-btn.close {
|
|
background: rgba(244, 67, 54, 0.8);
|
|
color: #fff;
|
|
}
|
|
|
|
.window-btn:hover {
|
|
transform: scale(1.1);
|
|
box-shadow: 0 0 10px currentColor;
|
|
}
|
|
|
|
.window-content {
|
|
flex: 1;
|
|
overflow: auto;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.window-resize {
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 15px;
|
|
height: 15px;
|
|
cursor: se-resize;
|
|
}
|
|
|
|
/* ==================== 任务栏 ==================== */
|
|
#taskbar {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 60px;
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(var(--glass-blur));
|
|
border-top: 1px solid var(--glass-border);
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 1rem;
|
|
z-index: 9999;
|
|
}
|
|
|
|
.start-btn {
|
|
width: 50px;
|
|
height: 50px;
|
|
background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple));
|
|
border: none;
|
|
border-radius: 10px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.5rem;
|
|
color: #fff;
|
|
margin-right: 1rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.start-btn:hover {
|
|
transform: scale(1.05);
|
|
box-shadow: 0 0 20px var(--neon-pink);
|
|
}
|
|
|
|
.taskbar-apps {
|
|
flex: 1;
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
overflow-x: auto;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.taskbar-app {
|
|
height: 45px;
|
|
min-width: 150px;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 0.8rem;
|
|
gap: 0.5rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.taskbar-app:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-color: var(--neon-cyan);
|
|
}
|
|
|
|
.taskbar-app.active {
|
|
background: rgba(191, 0, 255, 0.2);
|
|
border-color: var(--neon-purple);
|
|
}
|
|
|
|
.taskbar-app .icon {
|
|
color: var(--neon-cyan);
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
.taskbar-app .name {
|
|
font-size: 0.8rem;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.taskbar-system {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.system-tray {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.8rem;
|
|
padding: 0.5rem 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.tray-icon {
|
|
color: var(--text-secondary);
|
|
cursor: pointer;
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.tray-icon:hover {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.tray-time {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.85rem;
|
|
text-align: right;
|
|
}
|
|
|
|
.tray-time .time {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.tray-time .date {
|
|
font-size: 0.7rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* ==================== 开始菜单 ==================== */
|
|
#start-menu {
|
|
position: fixed;
|
|
bottom: 70px;
|
|
left: 1rem;
|
|
width: 350px;
|
|
max-height: 500px;
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(var(--glass-blur));
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 12px;
|
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
|
display: none;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
z-index: 10000;
|
|
}
|
|
|
|
#start-menu.active {
|
|
display: flex;
|
|
}
|
|
|
|
.start-header {
|
|
padding: 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
border-bottom: 1px solid var(--glass-border);
|
|
}
|
|
|
|
.start-avatar {
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple));
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.start-user-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.start-username {
|
|
font-weight: 500;
|
|
}
|
|
|
|
.start-user-title {
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.start-search {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.start-search input {
|
|
width: 100%;
|
|
padding: 0.8rem 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
color: var(--text-primary);
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.start-search input::placeholder {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.start-apps {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.start-section-title {
|
|
font-family: var(--font-display);
|
|
font-size: 0.75rem;
|
|
color: var(--text-muted);
|
|
padding: 0.5rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.1rem;
|
|
}
|
|
|
|
.start-app-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 0.5rem;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.start-app-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.8rem 0.5rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.start-app-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.start-app-item .icon {
|
|
font-size: 1.5rem;
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.start-app-item .name {
|
|
font-size: 0.7rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.start-footer {
|
|
padding: 1rem;
|
|
border-top: 1px solid var(--glass-border);
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.power-btn {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
background: rgba(255, 0, 68, 0.2);
|
|
border: 1px solid var(--neon-red);
|
|
color: var(--neon-red);
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.power-btn:hover {
|
|
background: var(--neon-red);
|
|
color: #fff;
|
|
}
|
|
|
|
/* ==================== 右键菜单 ==================== */
|
|
#context-menu {
|
|
position: fixed;
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(var(--glass-blur));
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
|
display: none;
|
|
flex-direction: column;
|
|
min-width: 200px;
|
|
padding: 0.5rem 0;
|
|
z-index: 100000;
|
|
}
|
|
|
|
.context-item {
|
|
padding: 0.6rem 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.8rem;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.context-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.context-item .icon {
|
|
color: var(--neon-cyan);
|
|
width: 20px;
|
|
}
|
|
|
|
.context-divider {
|
|
height: 1px;
|
|
background: var(--glass-border);
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
/* ==================== 通知系统 ==================== */
|
|
#notifications {
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
z-index: 100000;
|
|
}
|
|
|
|
.notification {
|
|
width: 300px;
|
|
padding: 1rem;
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(var(--glass-blur));
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.8rem;
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
animation: slideIn 0.3s ease;
|
|
}
|
|
|
|
@keyframes slideIn {
|
|
from {
|
|
transform: translateX(100%);
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.notification.success .icon { color: var(--neon-green); }
|
|
.notification.warning .icon { color: var(--neon-yellow); }
|
|
.notification.error .icon { color: var(--neon-red); }
|
|
.notification.info .icon { color: var(--neon-cyan); }
|
|
|
|
.notification-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.notification-title {
|
|
font-weight: 500;
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.notification-message {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* ==================== 应用内容样式 ==================== */
|
|
|
|
/* 文件管理器 */
|
|
.file-manager {
|
|
display: flex;
|
|
height: 100%;
|
|
}
|
|
|
|
.file-sidebar {
|
|
width: 200px;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
padding: 1rem;
|
|
border-right: 1px solid var(--glass-border);
|
|
}
|
|
|
|
.file-sidebar-item {
|
|
padding: 0.6rem 0.8rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.file-sidebar-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.file-sidebar-item.active {
|
|
background: rgba(191, 0, 255, 0.2);
|
|
border-left: 2px solid var(--neon-purple);
|
|
}
|
|
|
|
.file-content {
|
|
flex: 1;
|
|
padding: 1rem;
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
|
gap: 1rem;
|
|
align-content: start;
|
|
}
|
|
|
|
.file-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.file-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.file-item .icon {
|
|
font-size: 2.5rem;
|
|
}
|
|
|
|
.file-item.folder .icon { color: var(--neon-yellow); }
|
|
.file-item.document .icon { color: var(--neon-cyan); }
|
|
.file-item.image .icon { color: var(--neon-pink); }
|
|
.file-item.audio .icon { color: var(--neon-green); }
|
|
.file-item.video .icon { color: var(--neon-purple); }
|
|
|
|
.file-item span {
|
|
font-size: 0.8rem;
|
|
text-align: center;
|
|
word-break: break-word;
|
|
}
|
|
|
|
/* 终端 */
|
|
.terminal {
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.terminal-output {
|
|
height: calc(100% - 40px);
|
|
padding: 1rem;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.terminal-line {
|
|
margin-bottom: 0.3rem;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.terminal-line.command {
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.terminal-line.output {
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.terminal-line.error {
|
|
color: var(--neon-red);
|
|
}
|
|
|
|
.terminal-line.success {
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.terminal-line.info {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.terminal-line.ascii-art {
|
|
color: var(--neon-purple);
|
|
white-space: pre;
|
|
font-size: 0.7rem;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.terminal-input-line {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.5rem 1rem;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
border-top: 1px solid var(--glass-border);
|
|
}
|
|
|
|
.terminal-prompt {
|
|
color: var(--neon-green);
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
.terminal-input {
|
|
flex: 1;
|
|
background: transparent;
|
|
border: none;
|
|
color: var(--text-primary);
|
|
font-family: var(--font-mono);
|
|
font-size: 0.9rem;
|
|
outline: none;
|
|
}
|
|
|
|
/* 浏览器 */
|
|
.browser {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.browser-toolbar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-bottom: 1px solid var(--glass-border);
|
|
}
|
|
|
|
.browser-nav-btn {
|
|
width: 30px;
|
|
height: 30px;
|
|
border-radius: 50%;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border: none;
|
|
color: var(--text-primary);
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.browser-nav-btn:hover {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.browser-url {
|
|
flex: 1;
|
|
padding: 0.6rem 1rem;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 20px;
|
|
color: var(--text-primary);
|
|
font-family: var(--font-mono);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.browser-url:focus {
|
|
outline: none;
|
|
border-color: var(--neon-cyan);
|
|
}
|
|
|
|
.browser-content {
|
|
flex: 1;
|
|
background: #fff;
|
|
}
|
|
|
|
.browser-content iframe {
|
|
width: 100%;
|
|
height: 100%;
|
|
border: none;
|
|
}
|
|
|
|
/* 设置中心 */
|
|
.settings {
|
|
height: 100%;
|
|
display: flex;
|
|
}
|
|
|
|
.settings-sidebar {
|
|
width: 200px;
|
|
padding: 1rem;
|
|
border-right: 1px solid var(--glass-border);
|
|
}
|
|
|
|
.settings-nav-item {
|
|
padding: 0.8rem 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.8rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.settings-nav-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.settings-nav-item.active {
|
|
background: rgba(191, 0, 255, 0.2);
|
|
border-left: 2px solid var(--neon-purple);
|
|
}
|
|
|
|
.settings-content {
|
|
flex: 1;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.settings-section {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.settings-section h3 {
|
|
font-family: var(--font-display);
|
|
margin-bottom: 1rem;
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.settings-option {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-radius: 8px;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.settings-option label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.8rem;
|
|
}
|
|
|
|
.settings-option .icon {
|
|
color: var(--neon-purple);
|
|
}
|
|
|
|
/* 开关样式 */
|
|
.toggle-switch {
|
|
width: 50px;
|
|
height: 26px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 13px;
|
|
position: relative;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.toggle-switch.active {
|
|
background: var(--neon-purple);
|
|
}
|
|
|
|
.toggle-switch::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 3px;
|
|
left: 3px;
|
|
width: 20px;
|
|
height: 20px;
|
|
background: #fff;
|
|
border-radius: 50%;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.toggle-switch.active::after {
|
|
left: 27px;
|
|
}
|
|
|
|
/* 滑块样式 */
|
|
.slider {
|
|
width: 150px;
|
|
-webkit-appearance: none;
|
|
height: 6px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 3px;
|
|
outline: none;
|
|
}
|
|
|
|
.slider::-webkit-slider-thumb {
|
|
-webkit-appearance: none;
|
|
width: 18px;
|
|
height: 18px;
|
|
background: var(--neon-cyan);
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
box-shadow: 0 0 10px var(--neon-cyan);
|
|
}
|
|
|
|
/* 音乐播放器 */
|
|
.music-player {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.album-cover {
|
|
width: 200px;
|
|
height: 200px;
|
|
border-radius: 12px;
|
|
background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple));
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 4rem;
|
|
margin-bottom: 1.5rem;
|
|
box-shadow: 0 0 30px rgba(191, 0, 255, 0.4);
|
|
animation: rotate 20s linear infinite paused;
|
|
}
|
|
|
|
.album-cover.playing {
|
|
animation-play-state: running;
|
|
}
|
|
|
|
@keyframes rotate {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
.track-info {
|
|
text-align: center;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.track-title {
|
|
font-size: 1.2rem;
|
|
font-weight: 500;
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.track-artist {
|
|
font-size: 0.9rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.progress-container {
|
|
width: 100%;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.progress-bar {
|
|
width: 100%;
|
|
height: 6px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, var(--neon-cyan), var(--neon-pink));
|
|
border-radius: 3px;
|
|
width: 0%;
|
|
transition: width 0.1s linear;
|
|
}
|
|
|
|
.time-display {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary);
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.player-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.5rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.control-btn {
|
|
width: 45px;
|
|
height: 45px;
|
|
border-radius: 50%;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border: none;
|
|
color: var(--text-primary);
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.2rem;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.control-btn:hover {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.control-btn.play {
|
|
width: 55px;
|
|
height: 55px;
|
|
background: linear-gradient(135deg, var(--neon-pink), var(--neon-purple));
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.volume-control {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.8rem;
|
|
width: 100%;
|
|
max-width: 300px;
|
|
}
|
|
|
|
.volume-icon {
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.playlist {
|
|
width: 100%;
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.playlist-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding: 0.8rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.playlist-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.playlist-item.active {
|
|
background: rgba(191, 0, 255, 0.2);
|
|
}
|
|
|
|
.playlist-item .icon {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.playlist-item-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.playlist-item-title {
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.playlist-item-artist {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.playlist-item-duration {
|
|
font-size: 0.8rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* 便签应用 */
|
|
.notes-app {
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.notes-sidebar {
|
|
width: 200px;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-right: 1px solid var(--glass-border);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.notes-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
.note-item {
|
|
padding: 0.8rem;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
margin-bottom: 0.5rem;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.note-item:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.note-item.active {
|
|
background: rgba(191, 0, 255, 0.2);
|
|
border-left: 2px solid var(--neon-purple);
|
|
}
|
|
|
|
.note-item-title {
|
|
font-weight: 500;
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.note-item-preview {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.note-item-date {
|
|
font-size: 0.7rem;
|
|
color: var(--text-muted);
|
|
margin-top: 0.3rem;
|
|
}
|
|
|
|
.notes-editor {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.notes-title-input {
|
|
padding: 0.8rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
color: var(--text-primary);
|
|
font-size: 1.2rem;
|
|
font-weight: 500;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.notes-title-input:focus {
|
|
outline: none;
|
|
border-color: var(--neon-cyan);
|
|
}
|
|
|
|
.notes-content {
|
|
flex: 1;
|
|
padding: 1rem;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
color: var(--text-primary);
|
|
font-family: var(--font-body);
|
|
font-size: 0.95rem;
|
|
line-height: 1.6;
|
|
resize: none;
|
|
}
|
|
|
|
.notes-content:focus {
|
|
outline: none;
|
|
border-color: var(--neon-cyan);
|
|
}
|
|
|
|
.notes-toolbar {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.notes-toolbar button {
|
|
padding: 0.5rem 0.8rem;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 6px;
|
|
color: var(--text-primary);
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.notes-toolbar button:hover {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
/* 系统监控 */
|
|
.system-monitor {
|
|
height: 100%;
|
|
padding: 1rem;
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 1rem;
|
|
}
|
|
|
|
.monitor-chart {
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-radius: 12px;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.monitor-chart h4 {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.monitor-chart .icon {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.chart-container {
|
|
height: 150px;
|
|
}
|
|
|
|
.monitor-stats {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.stat-value {
|
|
font-family: var(--font-mono);
|
|
font-size: 1.2rem;
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* 矩阵雨特效 */
|
|
#matrix-canvas {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #000;
|
|
z-index: 99999;
|
|
display: none;
|
|
}
|
|
|
|
#matrix-canvas.active {
|
|
display: block;
|
|
}
|
|
|
|
/* ==================== 响应式设计 ==================== */
|
|
@media (max-width: 768px) {
|
|
.desktop-icons {
|
|
top: 10px;
|
|
left: 10px;
|
|
}
|
|
|
|
.desktop-icon {
|
|
width: 60px;
|
|
}
|
|
|
|
.desktop-icon .icon {
|
|
font-size: 2rem;
|
|
}
|
|
|
|
.desktop-widgets {
|
|
top: 10px;
|
|
right: 10px;
|
|
}
|
|
|
|
.widget {
|
|
width: 150px;
|
|
padding: 0.8rem;
|
|
}
|
|
|
|
.window {
|
|
min-width: 300px;
|
|
min-height: 250px;
|
|
}
|
|
|
|
.start-menu {
|
|
width: calc(100% - 2rem);
|
|
left: 1rem;
|
|
}
|
|
|
|
.start-app-grid {
|
|
grid-template-columns: repeat(4, 1fr);
|
|
}
|
|
|
|
.system-monitor {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- 启动动画 -->
|
|
<div id="boot-screen">
|
|
<div class="boot-logo">CYBEROS</div>
|
|
<div class="boot-loader">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</div>
|
|
<div class="boot-text">SYSTEM INITIALIZING...</div>
|
|
</div>
|
|
|
|
<!-- 锁屏界面 -->
|
|
<div id="lock-screen">
|
|
<div class="lock-time" id="lock-time">00:00</div>
|
|
<div class="lock-date" id="lock-date">2024年1月1日 星期一</div>
|
|
<div class="lock-avatar"><i class="fas fa-user"></i></div>
|
|
<div class="lock-username">CyberUser</div>
|
|
<input type="password" class="lock-password" id="lock-password" placeholder="输入密码 (任意密码)">
|
|
<div class="lock-hint">按 Enter 解锁系统</div>
|
|
</div>
|
|
|
|
<!-- 桌面 -->
|
|
<div id="desktop">
|
|
<div class="desktop-bg"></div>
|
|
<div class="grid-overlay"></div>
|
|
<div class="scanlines"></div>
|
|
|
|
<!-- 桌面图标 -->
|
|
<div class="desktop-icons">
|
|
<div class="desktop-icon" data-app="file-manager">
|
|
<i class="fas fa-folder icon"></i>
|
|
<span>文件管理器</span>
|
|
</div>
|
|
<div class="desktop-icon" data-app="terminal">
|
|
<i class="fas fa-terminal icon"></i>
|
|
<span>终端</span>
|
|
</div>
|
|
<div class="desktop-icon" data-app="browser">
|
|
<i class="fas fa-globe icon"></i>
|
|
<span>浏览器</span>
|
|
</div>
|
|
<div class="desktop-icon" data-app="settings">
|
|
<i class="fas fa-cog icon"></i>
|
|
<span>设置</span>
|
|
</div>
|
|
<div class="desktop-icon" data-app="music">
|
|
<i class="fas fa-music icon"></i>
|
|
<span>音乐</span>
|
|
</div>
|
|
<div class="desktop-icon" data-app="notes">
|
|
<i class="fas fa-sticky-note icon"></i>
|
|
<span>便签</span>
|
|
</div>
|
|
<div class="desktop-icon" data-app="monitor">
|
|
<i class="fas fa-chart-line icon"></i>
|
|
<span>系统监控</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 桌面小部件 -->
|
|
<div class="desktop-widgets">
|
|
<div class="widget widget-clock">
|
|
<div class="time" id="widget-time">00:00:00</div>
|
|
<div class="date" id="widget-date">2024年1月1日</div>
|
|
</div>
|
|
<div class="widget widget-calendar">
|
|
<div class="month" id="widget-month">1月</div>
|
|
<div class="day" id="widget-day">1</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 窗口容器 -->
|
|
<div id="windows-container"></div>
|
|
</div>
|
|
|
|
<!-- 任务栏 -->
|
|
<div id="taskbar">
|
|
<button class="start-btn" id="start-btn">
|
|
<i class="fas fa-th"></i>
|
|
</button>
|
|
<div class="taskbar-apps" id="taskbar-apps"></div>
|
|
<div class="taskbar-system">
|
|
<div class="system-tray">
|
|
<i class="fas fa-volume-up tray-icon" id="volume-icon"></i>
|
|
<i class="fas fa-wifi tray-icon"></i>
|
|
<i class="fas fa-battery-three-quarters tray-icon"></i>
|
|
<div class="tray-time">
|
|
<div class="time" id="tray-time">00:00</div>
|
|
<div class="date" id="tray-date">1/1</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 开始菜单 -->
|
|
<div id="start-menu">
|
|
<div class="start-header">
|
|
<div class="start-avatar"><i class="fas fa-user"></i></div>
|
|
<div class="start-user-info">
|
|
<div class="start-username">CyberUser</div>
|
|
<div class="start-user-title">系统管理员</div>
|
|
</div>
|
|
</div>
|
|
<div class="start-search">
|
|
<input type="text" placeholder="搜索应用和文件...">
|
|
</div>
|
|
<div class="start-apps">
|
|
<div class="start-section-title">已固定的应用</div>
|
|
<div class="start-app-grid" id="start-app-grid"></div>
|
|
</div>
|
|
<div class="start-footer">
|
|
<button class="power-btn" id="power-btn" title="关机">
|
|
<i class="fas fa-power-off"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 右键菜单 -->
|
|
<div id="context-menu">
|
|
<div class="context-item" data-action="refresh">
|
|
<i class="fas fa-sync-alt icon"></i>
|
|
<span>刷新</span>
|
|
</div>
|
|
<div class="context-divider"></div>
|
|
<div class="context-item" data-action="settings">
|
|
<i class="fas fa-cog icon"></i>
|
|
<span>显示设置</span>
|
|
</div>
|
|
<div class="context-item" data-action="personalize">
|
|
<i class="fas fa-palette icon"></i>
|
|
<span>个性化</span>
|
|
</div>
|
|
<div class="context-divider"></div>
|
|
<div class="context-item" data-action="terminal">
|
|
<i class="fas fa-terminal icon"></i>
|
|
<span>打开终端</span>
|
|
</div>
|
|
<div class="context-divider"></div>
|
|
<div class="context-item" data-action="about">
|
|
<i class="fas fa-info-circle icon"></i>
|
|
<span>关于系统</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 通知容器 -->
|
|
<div id="notifications"></div>
|
|
|
|
<!-- 矩阵雨特效 Canvas -->
|
|
<canvas id="matrix-canvas"></canvas>
|
|
|
|
<script>
|
|
// ==================== 全局状态管理 ====================
|
|
const state = {
|
|
windows: new Map(),
|
|
windowIdCounter: 0,
|
|
activeWindowId: null,
|
|
zIndexCounter: 100,
|
|
isBooting: true,
|
|
isLocked: true,
|
|
startMenuOpen: false,
|
|
contextMenuOpen: false,
|
|
settings: {
|
|
theme: 'default',
|
|
wallpaper: 'default',
|
|
volume: 80
|
|
},
|
|
notes: JSON.parse(localStorage.getItem('cyberos_notes') || '[]'),
|
|
terminalHistory: [],
|
|
terminalHistoryIndex: -1,
|
|
musicPlaying: false,
|
|
musicProgress: 0
|
|
};
|
|
|
|
// ==================== 工具函数 ====================
|
|
function generateId() {
|
|
return 'window-' + (++state.windowIdCounter);
|
|
}
|
|
|
|
function formatTime(date = new Date()) {
|
|
const hours = String(date.getHours()).padStart(2, '0');
|
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
return `${hours}:${minutes}:${seconds}`;
|
|
}
|
|
|
|
function formatDate(date = new Date()) {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
|
return `${year}年${month}月${day}日 ${weekdays[date.getDay()]}`;
|
|
}
|
|
|
|
function formatShortDate(date = new Date()) {
|
|
return `${date.getMonth() + 1}/${date.getDate()}`;
|
|
}
|
|
|
|
function showNotification(title, message, type = 'info') {
|
|
const container = document.getElementById('notifications');
|
|
const notification = document.createElement('div');
|
|
notification.className = `notification ${type}`;
|
|
notification.innerHTML = `
|
|
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'warning' ? 'exclamation-triangle' : type === 'error' ? 'times-circle' : 'info-circle'} icon"></i>
|
|
<div class="notification-content">
|
|
<div class="notification-title">${title}</div>
|
|
<div class="notification-message">${message}</div>
|
|
</div>
|
|
`;
|
|
container.appendChild(notification);
|
|
|
|
setTimeout(() => {
|
|
notification.style.animation = 'slideIn 0.3s ease reverse';
|
|
setTimeout(() => notification.remove(), 300);
|
|
}, 4000);
|
|
}
|
|
|
|
// ==================== 启动流程 ====================
|
|
function initBoot() {
|
|
const bootScreen = document.getElementById('boot-screen');
|
|
const lockScreen = document.getElementById('lock-screen');
|
|
|
|
// 启动动画
|
|
setTimeout(() => {
|
|
anime({
|
|
targets: bootScreen,
|
|
opacity: 0,
|
|
duration: 500,
|
|
easing: 'easeOutQuad',
|
|
complete: () => {
|
|
bootScreen.style.display = 'none';
|
|
lockScreen.classList.add('active');
|
|
updateLockTime();
|
|
|
|
// 绑定锁屏密码事件
|
|
const lockPassword = document.getElementById('lock-password');
|
|
if (lockPassword) {
|
|
lockPassword.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
unlockSystem();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}, 2500);
|
|
}
|
|
|
|
function updateLockTime() {
|
|
const timeEl = document.getElementById('lock-time');
|
|
const dateEl = document.getElementById('lock-date');
|
|
timeEl.textContent = formatTime();
|
|
dateEl.textContent = formatDate();
|
|
requestAnimationFrame(updateLockTime);
|
|
}
|
|
|
|
function unlockSystem() {
|
|
const lockScreen = document.getElementById('lock-screen');
|
|
lockScreen.classList.remove('active');
|
|
state.isLocked = false;
|
|
state.isBooting = false;
|
|
showNotification('欢迎', '欢迎使用 CyberOS 赛博朋克操作系统', 'success');
|
|
initDesktop();
|
|
}
|
|
|
|
// ==================== 窗口管理器 ====================
|
|
class WindowManager {
|
|
static create(appId, title, content, options = {}) {
|
|
const id = generateId();
|
|
const {
|
|
icon = 'fa-window-maximize',
|
|
width = 800,
|
|
height = 500,
|
|
x = 100 + (state.windowIdCounter * 30),
|
|
y = 50 + (state.windowIdCounter * 30),
|
|
resizable = true
|
|
} = options;
|
|
|
|
const container = document.getElementById('windows-container');
|
|
const windowEl = document.createElement('div');
|
|
windowEl.className = 'window';
|
|
windowEl.id = id;
|
|
windowEl.style.width = width + 'px';
|
|
windowEl.style.height = height + 'px';
|
|
windowEl.style.left = x + 'px';
|
|
windowEl.style.top = y + 'px';
|
|
windowEl.style.zIndex = ++state.zIndexCounter;
|
|
|
|
windowEl.innerHTML = `
|
|
<div class="window-header">
|
|
<i class="fas ${icon} window-icon"></i>
|
|
<span class="window-title">${title}</span>
|
|
<div class="window-controls">
|
|
<button class="window-btn minimize" title="最小化"><i class="fas fa-minus"></i></button>
|
|
<button class="window-btn maximize" title="最大化"><i class="fas fa-expand"></i></button>
|
|
<button class="window-btn close" title="关闭"><i class="fas fa-times"></i></button>
|
|
</div>
|
|
</div>
|
|
<div class="window-content">${content}</div>
|
|
${resizable ? '<div class="window-resize"></div>' : ''}
|
|
`;
|
|
|
|
container.appendChild(windowEl);
|
|
|
|
state.windows.set(id, {
|
|
id,
|
|
appId,
|
|
title,
|
|
icon,
|
|
minimized: false,
|
|
maximized: false,
|
|
element: windowEl
|
|
});
|
|
|
|
this.bindWindowEvents(windowEl, id);
|
|
this.focusWindow(id);
|
|
this.updateTaskbar();
|
|
|
|
// 窗口打开动画
|
|
anime({
|
|
targets: windowEl,
|
|
scale: [0.8, 1],
|
|
opacity: [0, 1],
|
|
duration: 300,
|
|
easing: 'easeOutBack'
|
|
});
|
|
|
|
return id;
|
|
}
|
|
|
|
static bindWindowEvents(windowEl, id) {
|
|
const header = windowEl.querySelector('.window-header');
|
|
const minimizeBtn = windowEl.querySelector('.minimize');
|
|
const maximizeBtn = windowEl.querySelector('.maximize');
|
|
const closeBtn = windowEl.querySelector('.close');
|
|
const resizeHandle = windowEl.querySelector('.window-resize');
|
|
|
|
// 拖拽
|
|
let isDragging = false;
|
|
let dragOffset = { x: 0, y: 0 };
|
|
|
|
header.addEventListener('mousedown', (e) => {
|
|
if (e.target.closest('.window-controls')) return;
|
|
isDragging = true;
|
|
dragOffset.x = e.clientX - windowEl.offsetLeft;
|
|
dragOffset.y = e.clientY - windowEl.offsetTop;
|
|
this.focusWindow(id);
|
|
});
|
|
|
|
document.addEventListener('mousemove', (e) => {
|
|
if (!isDragging) return;
|
|
windowEl.style.left = (e.clientX - dragOffset.x) + 'px';
|
|
windowEl.style.top = (e.clientY - dragOffset.y) + 'px';
|
|
});
|
|
|
|
document.addEventListener('mouseup', () => {
|
|
isDragging = false;
|
|
});
|
|
|
|
// 调整大小
|
|
if (resizeHandle) {
|
|
let isResizing = false;
|
|
let resizeStart = { x: 0, y: 0, w: 0, h: 0 };
|
|
|
|
resizeHandle.addEventListener('mousedown', (e) => {
|
|
isResizing = true;
|
|
resizeStart = {
|
|
x: e.clientX,
|
|
y: e.clientY,
|
|
w: windowEl.offsetWidth,
|
|
h: windowEl.offsetHeight
|
|
};
|
|
e.stopPropagation();
|
|
});
|
|
|
|
document.addEventListener('mousemove', (e) => {
|
|
if (!isResizing) return;
|
|
const newWidth = Math.max(400, resizeStart.w + (e.clientX - resizeStart.x));
|
|
const newHeight = Math.max(300, resizeStart.h + (e.clientY - resizeStart.y));
|
|
windowEl.style.width = newWidth + 'px';
|
|
windowEl.style.height = newHeight + 'px';
|
|
});
|
|
|
|
document.addEventListener('mouseup', () => {
|
|
isResizing = false;
|
|
});
|
|
}
|
|
|
|
// 按钮事件
|
|
minimizeBtn.addEventListener('click', () => this.minimize(id));
|
|
maximizeBtn.addEventListener('click', () => this.toggleMaximize(id));
|
|
closeBtn.addEventListener('click', () => this.close(id));
|
|
|
|
// 点击聚焦
|
|
windowEl.addEventListener('mousedown', () => {
|
|
this.focusWindow(id);
|
|
});
|
|
}
|
|
|
|
static focusWindow(id) {
|
|
const winData = state.windows.get(id);
|
|
if (!winData) return;
|
|
|
|
state.activeWindowId = id;
|
|
|
|
state.windows.forEach((data, wid) => {
|
|
if (wid === id) {
|
|
data.element.style.zIndex = ++state.zIndexCounter;
|
|
data.element.classList.add('active');
|
|
data.element.classList.remove('inactive');
|
|
} else {
|
|
data.element.classList.remove('active');
|
|
data.element.classList.add('inactive');
|
|
}
|
|
});
|
|
|
|
this.updateTaskbar();
|
|
}
|
|
|
|
static minimize(id) {
|
|
const winData = state.windows.get(id);
|
|
if (!winData) return;
|
|
|
|
winData.minimized = true;
|
|
winData.element.style.display = 'none';
|
|
this.updateTaskbar();
|
|
}
|
|
|
|
static restore(id) {
|
|
const winData = state.windows.get(id);
|
|
if (!winData) return;
|
|
|
|
winData.minimized = false;
|
|
winData.element.style.display = 'flex';
|
|
this.focusWindow(id);
|
|
}
|
|
|
|
static toggleMaximize(id) {
|
|
const winData = state.windows.get(id);
|
|
if (!winData) return;
|
|
|
|
winData.maximized = !winData.maximized;
|
|
const winEl = winData.element;
|
|
|
|
if (winData.maximized) {
|
|
winEl.dataset.prevLeft = winEl.style.left;
|
|
winEl.dataset.prevTop = winEl.style.top;
|
|
winEl.dataset.prevWidth = winEl.style.width;
|
|
winEl.dataset.prevHeight = winEl.style.height;
|
|
winEl.style.left = '0';
|
|
winEl.style.top = '0';
|
|
winEl.style.width = '100%';
|
|
winEl.style.height = 'calc(100% - 60px)';
|
|
} else {
|
|
winEl.style.left = winEl.dataset.prevLeft;
|
|
winEl.style.top = winEl.dataset.prevTop;
|
|
winEl.style.width = winEl.dataset.prevWidth;
|
|
winEl.style.height = winEl.dataset.prevHeight;
|
|
}
|
|
}
|
|
|
|
static close(id) {
|
|
const winData = state.windows.get(id);
|
|
if (!winData) return;
|
|
|
|
anime({
|
|
targets: winData.element,
|
|
scale: 0.8,
|
|
opacity: 0,
|
|
duration: 200,
|
|
easing: 'easeInQuad',
|
|
complete: () => {
|
|
winData.element.remove();
|
|
state.windows.delete(id);
|
|
this.updateTaskbar();
|
|
}
|
|
});
|
|
}
|
|
|
|
static updateTaskbar() {
|
|
const container = document.getElementById('taskbar-apps');
|
|
container.innerHTML = '';
|
|
|
|
state.windows.forEach((data) => {
|
|
const item = document.createElement('div');
|
|
item.className = 'taskbar-app' + (data.id === state.activeWindowId ? ' active' : '');
|
|
item.innerHTML = `
|
|
<i class="fas ${data.icon} icon"></i>
|
|
<span class="name">${data.title}</span>
|
|
`;
|
|
item.addEventListener('click', () => {
|
|
if (data.minimized || data.id !== state.activeWindowId) {
|
|
this.restore(data.id);
|
|
} else {
|
|
this.minimize(data.id);
|
|
}
|
|
});
|
|
container.appendChild(item);
|
|
});
|
|
}
|
|
}
|
|
|
|
// ==================== 应用模块 ====================
|
|
|
|
// 文件管理器
|
|
function openFileManager() {
|
|
const content = `
|
|
<div class="file-manager">
|
|
<div class="file-sidebar">
|
|
<div class="file-sidebar-item active">
|
|
<i class="fas fa-home"></i>
|
|
<span>主页</span>
|
|
</div>
|
|
<div class="file-sidebar-item">
|
|
<i class="fas fa-desktop"></i>
|
|
<span>桌面</span>
|
|
</div>
|
|
<div class="file-sidebar-item">
|
|
<i class="fas fa-download"></i>
|
|
<span>下载</span>
|
|
</div>
|
|
<div class="file-sidebar-item">
|
|
<i class="fas fa-music"></i>
|
|
<span>音乐</span>
|
|
</div>
|
|
<div class="file-sidebar-item">
|
|
<i class="fas fa-image"></i>
|
|
<span>图片</span>
|
|
</div>
|
|
<div class="file-sidebar-item">
|
|
<i class="fas fa-video"></i>
|
|
<span>视频</span>
|
|
</div>
|
|
<div class="file-sidebar-item">
|
|
<i class="fas fa-hdd"></i>
|
|
<span>本地磁盘</span>
|
|
</div>
|
|
</div>
|
|
<div class="file-content">
|
|
<div class="file-item folder">
|
|
<i class="fas fa-folder icon"></i>
|
|
<span>项目文件</span>
|
|
</div>
|
|
<div class="file-item folder">
|
|
<i class="fas fa-folder icon"></i>
|
|
<span>工作文档</span>
|
|
</div>
|
|
<div class="file-item folder">
|
|
<i class="fas fa-folder icon"></i>
|
|
<span>图片素材</span>
|
|
</div>
|
|
<div class="file-item document">
|
|
<i class="fas fa-file-alt icon"></i>
|
|
<span>readme.txt</span>
|
|
</div>
|
|
<div class="file-item document">
|
|
<i class="fas fa-file-code icon"></i>
|
|
<span>index.html</span>
|
|
</div>
|
|
<div class="file-item image">
|
|
<i class="fas fa-file-image icon"></i>
|
|
<span>wallpaper.jpg</span>
|
|
</div>
|
|
<div class="file-item audio">
|
|
<i class="fas fa-file-audio icon"></i>
|
|
<span>cyberpunk.mp3</span>
|
|
</div>
|
|
<div class="file-item video">
|
|
<i class="fas fa-file-video icon"></i>
|
|
<span>demo.mp4</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
WindowManager.create('file-manager', '文件管理器', content, { icon: 'fa-folder' });
|
|
}
|
|
|
|
// 终端
|
|
function openTerminal() {
|
|
const content = `
|
|
<div class="terminal">
|
|
<div class="terminal-output" id="terminal-output">
|
|
<div class="terminal-line info">CyberOS Terminal v2.0.0</div>
|
|
<div class="terminal-line output">输入 'help' 查看可用命令</div>
|
|
<br>
|
|
</div>
|
|
<div class="terminal-input-line">
|
|
<span class="terminal-prompt">user@cyberos:~$</span>
|
|
<input type="text" class="terminal-input" id="terminal-input" autofocus>
|
|
</div>
|
|
</div>
|
|
`;
|
|
const windowId = WindowManager.create('terminal', '终端', content, {
|
|
icon: 'fa-terminal',
|
|
width: 700,
|
|
height: 450
|
|
});
|
|
|
|
setTimeout(() => {
|
|
initTerminal(windowId);
|
|
}, 100);
|
|
}
|
|
|
|
function initTerminal(windowId) {
|
|
const output = document.getElementById('terminal-output');
|
|
const input = document.getElementById('terminal-input');
|
|
|
|
if (!output || !input) return;
|
|
|
|
const terminalEl = output.closest('.window');
|
|
output.innerHTML = `
|
|
<div class="terminal-line info">CyberOS Terminal v2.0.0</div>
|
|
<div class="terminal-line output">输入 'help' 查看可用命令</div>
|
|
<br>
|
|
`;
|
|
|
|
const appendLine = (text, className = 'output') => {
|
|
const line = document.createElement('div');
|
|
line.className = `terminal-line ${className}`;
|
|
line.textContent = text;
|
|
output.appendChild(line);
|
|
output.scrollTop = output.scrollHeight;
|
|
};
|
|
|
|
const executeCommand = (cmd) => {
|
|
const args = cmd.trim().split(' ');
|
|
const command = args[0].toLowerCase();
|
|
const param = args.slice(1).join(' ');
|
|
|
|
appendLine(`user@cyberos:~$ ${cmd}`, 'command');
|
|
|
|
switch (command) {
|
|
case 'help':
|
|
appendLine('可用命令:', 'info');
|
|
appendLine(' help - 显示帮助信息', 'output');
|
|
appendLine(' clear - 清屏', 'output');
|
|
appendLine(' date - 显示当前日期时间', 'output');
|
|
appendLine(' whoami - 显示当前用户', 'output');
|
|
appendLine(' ls/dir - 列出文件', 'output');
|
|
appendLine(' cd - 切换目录', 'output');
|
|
appendLine(' cat/type - 查看文件内容', 'output');
|
|
appendLine(' echo - 输出文本', 'output');
|
|
appendLine(' neofetch - 显示系统信息', 'output');
|
|
appendLine(' matrix - 启动矩阵雨特效', 'output');
|
|
appendLine(' theme - 切换系统主题', 'output');
|
|
appendLine(' reboot - 重启系统', 'output');
|
|
break;
|
|
|
|
case 'clear':
|
|
output.innerHTML = '';
|
|
break;
|
|
|
|
case 'date':
|
|
appendLine(formatDate() + ' ' + formatTime(), 'output');
|
|
break;
|
|
|
|
case 'whoami':
|
|
appendLine('cyberuser', 'output');
|
|
break;
|
|
|
|
case 'ls':
|
|
case 'dir':
|
|
appendLine(' 文档 文件夹', 'output');
|
|
appendLine(' 下载 文件夹', 'output');
|
|
appendLine(' 图片 文件夹', 'output');
|
|
appendLine(' 桌面 文件夹', 'output');
|
|
appendLine(' readme.txt 文件', 'output');
|
|
break;
|
|
|
|
case 'cd':
|
|
appendLine(`切换到目录: ${param || '/home/user'}`, 'output');
|
|
break;
|
|
|
|
case 'cat':
|
|
case 'type':
|
|
appendLine(`这是文件 ${param || 'unknown'} 的内容。`, 'output');
|
|
appendLine('CyberOS - 赛博朋克操作系统', 'output');
|
|
break;
|
|
|
|
case 'echo':
|
|
appendLine(param || ' ', 'output');
|
|
break;
|
|
|
|
case 'neofetch':
|
|
appendLine(' .--. ' + process.env.USER + '@cyberos', 'ascii-art');
|
|
appendLine(' ..\'\'_......__ -----------------', 'ascii-art');
|
|
appendLine(' \'__\' | / \\ OS: CyberOS 2.0', 'ascii-art');
|
|
appendLine(' / \\ | / \\ Kernel: HTML5', 'ascii-art');
|
|
appendLine(' | | | | | Uptime: ' + Math.floor(performance.now() / 1000) + 's', 'ascii-art');
|
|
appendLine(' \\___/ |____|_____| Shell: cyber-sh', 'ascii-art');
|
|
break;
|
|
|
|
case 'matrix':
|
|
startMatrixEffect();
|
|
break;
|
|
|
|
case 'theme':
|
|
appendLine('主题切换中...', 'success');
|
|
showNotification('主题', '系统主题已切换', 'info');
|
|
break;
|
|
|
|
case 'reboot':
|
|
appendLine('系统重启中...', 'warning');
|
|
setTimeout(() => {
|
|
location.reload();
|
|
}, 2000);
|
|
break;
|
|
|
|
case '':
|
|
break;
|
|
|
|
default:
|
|
appendLine(`命令未找到: ${command}`, 'error');
|
|
appendLine("输入 'help' 查看可用命令", 'output');
|
|
}
|
|
};
|
|
|
|
input.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
const cmd = input.value;
|
|
input.value = '';
|
|
state.terminalHistory.push(cmd);
|
|
state.terminalHistoryIndex = state.terminalHistory.length;
|
|
executeCommand(cmd);
|
|
} else if (e.key === 'ArrowUp') {
|
|
if (state.terminalHistoryIndex > 0) {
|
|
state.terminalHistoryIndex--;
|
|
input.value = state.terminalHistory[state.terminalHistoryIndex];
|
|
}
|
|
e.preventDefault();
|
|
} else if (e.key === 'ArrowDown') {
|
|
if (state.terminalHistoryIndex < state.terminalHistory.length - 1) {
|
|
state.terminalHistoryIndex++;
|
|
input.value = state.terminalHistory[state.terminalHistoryIndex];
|
|
} else {
|
|
state.terminalHistoryIndex = state.terminalHistory.length;
|
|
input.value = '';
|
|
}
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
|
|
terminalEl.addEventListener('click', () => {
|
|
input.focus();
|
|
});
|
|
}
|
|
|
|
// 矩阵雨特效
|
|
function startMatrixEffect() {
|
|
const canvas = document.getElementById('matrix-canvas');
|
|
canvas.classList.add('active');
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()_+-=[]{}|;:,.<>?';
|
|
const fontSize = 14;
|
|
const columns = canvas.width / fontSize;
|
|
const drops = [];
|
|
|
|
for (let i = 0; i < columns; i++) {
|
|
drops[i] = Math.random() * -100;
|
|
}
|
|
|
|
function draw() {
|
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
ctx.fillStyle = '#0F0';
|
|
ctx.font = fontSize + 'px monospace';
|
|
|
|
for (let i = 0; i < drops.length; i++) {
|
|
const char = chars[Math.floor(Math.random() * chars.length)];
|
|
ctx.fillText(char, i * fontSize, drops[i] * fontSize);
|
|
|
|
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
|
|
drops[i] = 0;
|
|
}
|
|
drops[i]++;
|
|
}
|
|
}
|
|
|
|
const interval = setInterval(draw, 33);
|
|
|
|
const stopMatrix = () => {
|
|
clearInterval(interval);
|
|
canvas.classList.remove('active');
|
|
document.removeEventListener('click', stopMatrix);
|
|
document.removeEventListener('keydown', stopMatrix);
|
|
};
|
|
|
|
setTimeout(() => {
|
|
document.addEventListener('click', stopMatrix, { once: true });
|
|
document.addEventListener('keydown', stopMatrix, { once: true });
|
|
}, 10000);
|
|
}
|
|
|
|
// 浏览器
|
|
function openBrowser() {
|
|
const content = `
|
|
<div class="browser">
|
|
<div class="browser-toolbar">
|
|
<button class="browser-nav-btn"><i class="fas fa-arrow-left"></i></button>
|
|
<button class="browser-nav-btn"><i class="fas fa-arrow-right"></i></button>
|
|
<button class="browser-nav-btn"><i class="fas fa-redo"></i></button>
|
|
<input type="text" class="browser-url" id="browser-url" value="https://www.example.com" placeholder="输入网址...">
|
|
<button class="browser-nav-btn" id="browser-go"><i class="fas fa-arrow-right"></i></button>
|
|
</div>
|
|
<div class="browser-content">
|
|
<iframe id="browser-iframe" src="https://www.example.com"></iframe>
|
|
</div>
|
|
</div>
|
|
`;
|
|
const windowId = WindowManager.create('browser', '浏览器', content, {
|
|
icon: 'fa-globe',
|
|
width: 900,
|
|
height: 600
|
|
});
|
|
|
|
setTimeout(() => {
|
|
const urlInput = document.getElementById('browser-url');
|
|
const goBtn = document.getElementById('browser-go');
|
|
const iframe = document.getElementById('browser-iframe');
|
|
|
|
if (goBtn) {
|
|
goBtn.addEventListener('click', () => {
|
|
let url = urlInput.value.trim();
|
|
if (url && !url.startsWith('http')) {
|
|
url = 'https://' + url;
|
|
}
|
|
iframe.src = url;
|
|
});
|
|
}
|
|
|
|
if (urlInput) {
|
|
urlInput.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter') {
|
|
goBtn.click();
|
|
}
|
|
});
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
// 设置中心
|
|
function openSettings() {
|
|
const content = `
|
|
<div class="settings">
|
|
<div class="settings-sidebar">
|
|
<div class="settings-nav-item active">
|
|
<i class="fas fa-desktop"></i>
|
|
<span>显示</span>
|
|
</div>
|
|
<div class="settings-nav-item">
|
|
<i class="fas fa-volume-up"></i>
|
|
<span>声音</span>
|
|
</div>
|
|
<div class="settings-nav-item">
|
|
<i class="fas fa-palette"></i>
|
|
<span>个性化</span>
|
|
</div>
|
|
<div class="settings-nav-item">
|
|
<i class="fas fa-user"></i>
|
|
<span>账户</span>
|
|
</div>
|
|
<div class="settings-nav-item">
|
|
<i class="fas fa-shield-alt"></i>
|
|
<span>隐私</span>
|
|
</div>
|
|
<div class="settings-nav-item">
|
|
<i class="fas fa-info-circle"></i>
|
|
<span>关于</span>
|
|
</div>
|
|
</div>
|
|
<div class="settings-content">
|
|
<div class="settings-section">
|
|
<h3><i class="fas fa-desktop"></i> 显示设置</h3>
|
|
<div class="settings-option">
|
|
<label>
|
|
<i class="fas fa-moon icon"></i>
|
|
<span>深色模式</span>
|
|
</label>
|
|
<div class="toggle-switch active" onclick="this.classList.toggle('active')"></div>
|
|
</div>
|
|
<div class="settings-option">
|
|
<label>
|
|
<i class="fas fa-adjust icon"></i>
|
|
<span>自动调节亮度</span>
|
|
</label>
|
|
<div class="toggle-switch" onclick="this.classList.toggle('active')"></div>
|
|
</div>
|
|
</div>
|
|
<div class="settings-section">
|
|
<h3><i class="fas fa-volume-up"></i> 声音设置</h3>
|
|
<div class="settings-option">
|
|
<label>
|
|
<i class="fas fa-volume-up icon"></i>
|
|
<span>系统音量</span>
|
|
</label>
|
|
<input type="range" class="slider" value="80" min="0" max="100">
|
|
</div>
|
|
<div class="settings-option">
|
|
<label>
|
|
<i class="fas fa-bell icon"></i>
|
|
<span>通知声音</span>
|
|
</label>
|
|
<div class="toggle-switch active" onclick="this.classList.toggle('active')"></div>
|
|
</div>
|
|
</div>
|
|
<div class="settings-section">
|
|
<h3><i class="fas fa-shield-alt"></i> 隐私设置</h3>
|
|
<div class="settings-option">
|
|
<label>
|
|
<i class="fas fa-eye icon"></i>
|
|
<span>显示通知</span>
|
|
</label>
|
|
<div class="toggle-switch active" onclick="this.classList.toggle('active')"></div>
|
|
</div>
|
|
<div class="settings-option">
|
|
<label>
|
|
<i class="fas fa-location-arrow icon"></i>
|
|
<span>位置服务</span>
|
|
</label>
|
|
<div class="toggle-switch" onclick="this.classList.toggle('active')"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
WindowManager.create('settings', '设置', content, {
|
|
icon: 'fa-cog',
|
|
width: 750,
|
|
height: 500
|
|
});
|
|
}
|
|
|
|
// 音乐播放器
|
|
function openMusic() {
|
|
const content = `
|
|
<div class="music-player">
|
|
<div class="album-cover" id="album-cover">
|
|
<i class="fas fa-music"></i>
|
|
</div>
|
|
<div class="track-info">
|
|
<div class="track-title">Cyber Dreams</div>
|
|
<div class="track-artist">Neon Pulse</div>
|
|
</div>
|
|
<div class="progress-container">
|
|
<div class="progress-bar" id="progress-bar">
|
|
<div class="progress-fill" id="progress-fill"></div>
|
|
</div>
|
|
<div class="time-display">
|
|
<span id="current-time">0:00</span>
|
|
<span id="total-time">3:45</span>
|
|
</div>
|
|
</div>
|
|
<div class="player-controls">
|
|
<button class="control-btn"><i class="fas fa-random"></i></button>
|
|
<button class="control-btn"><i class="fas fa-step-backward"></i></button>
|
|
<button class="control-btn play" id="play-btn"><i class="fas fa-play"></i></button>
|
|
<button class="control-btn"><i class="fas fa-step-forward"></i></button>
|
|
<button class="control-btn"><i class="fas fa-redo"></i></button>
|
|
</div>
|
|
<div class="volume-control">
|
|
<i class="fas fa-volume-down volume-icon"></i>
|
|
<input type="range" class="slider" value="80" id="volume-slider">
|
|
<i class="fas fa-volume-up volume-icon"></i>
|
|
</div>
|
|
<div class="playlist">
|
|
<div class="playlist-item active">
|
|
<i class="fas fa-music icon"></i>
|
|
<div class="playlist-item-info">
|
|
<div class="playlist-item-title">Cyber Dreams</div>
|
|
<div class="playlist-item-artist">Neon Pulse</div>
|
|
</div>
|
|
<span class="playlist-item-duration">3:45</span>
|
|
</div>
|
|
<div class="playlist-item">
|
|
<i class="fas fa-music icon"></i>
|
|
<div class="playlist-item-info">
|
|
<div class="playlist-item-title">Neon Nights</div>
|
|
<div class="playlist-item-artist">Cyber Wave</div>
|
|
</div>
|
|
<span class="playlist-item-duration">4:12</span>
|
|
</div>
|
|
<div class="playlist-item">
|
|
<i class="fas fa-music icon"></i>
|
|
<div class="playlist-item-info">
|
|
<div class="playlist-item-title">Electric City</div>
|
|
<div class="playlist-item-artist">Synth Masters</div>
|
|
</div>
|
|
<span class="playlist-item-duration">3:58</span>
|
|
</div>
|
|
<div class="playlist-item">
|
|
<i class="fas fa-music icon"></i>
|
|
<div class="playlist-item-info">
|
|
<div class="playlist-item-title">Future Flash</div>
|
|
<div class="playlist-item-artist">Digital Dreams</div>
|
|
</div>
|
|
<span class="playlist-item-duration">4:30</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
const windowId = WindowManager.create('music', '音乐', content, {
|
|
icon: 'fa-music',
|
|
width: 400,
|
|
height: 600
|
|
});
|
|
|
|
setTimeout(() => {
|
|
const playBtn = document.getElementById('play-btn');
|
|
const albumCover = document.getElementById('album-cover');
|
|
const progressFill = document.getElementById('progress-fill');
|
|
const progressBar = document.getElementById('progress-bar');
|
|
|
|
if (playBtn) {
|
|
let playing = false;
|
|
let progress = 0;
|
|
|
|
playBtn.addEventListener('click', () => {
|
|
playing = !playing;
|
|
playBtn.innerHTML = `<i class="fas ${playing ? 'fa-pause' : 'fa-play'}"></i>`;
|
|
if (albumCover) {
|
|
albumCover.classList.toggle('playing', playing);
|
|
}
|
|
|
|
if (playing) {
|
|
const interval = setInterval(() => {
|
|
if (!playing) {
|
|
clearInterval(interval);
|
|
return;
|
|
}
|
|
progress += 0.5;
|
|
if (progress > 100) {
|
|
progress = 0;
|
|
}
|
|
if (progressFill) {
|
|
progressFill.style.width = progress + '%';
|
|
}
|
|
}, 100);
|
|
}
|
|
});
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
// 便签应用
|
|
function openNotes() {
|
|
const content = `
|
|
<div class="notes-app">
|
|
<div class="notes-sidebar">
|
|
<div style="padding: 1rem; display: flex; justify-content: space-between; align-items: center;">
|
|
<span style="font-weight: 500;">我的便签</span>
|
|
<button id="new-note-btn" style="background: var(--neon-purple); border: none; color: #fff; width: 28px; height: 28px; border-radius: 50%; cursor: pointer;">
|
|
<i class="fas fa-plus"></i>
|
|
</button>
|
|
</div>
|
|
<div class="notes-list" id="notes-list"></div>
|
|
</div>
|
|
<div class="notes-editor">
|
|
<div class="notes-toolbar">
|
|
<button onclick="document.execCommand('bold')"><i class="fas fa-bold"></i></button>
|
|
<button onclick="document.execCommand('italic')"><i class="fas fa-italic"></i></button>
|
|
<button onclick="document.execCommand('underline')"><i class="fas fa-underline"></i></button>
|
|
</div>
|
|
<input type="text" class="notes-title-input" id="note-title" placeholder="无标题便签">
|
|
<textarea class="notes-content" id="note-content" placeholder="开始书写..."></textarea>
|
|
</div>
|
|
</div>
|
|
`;
|
|
WindowManager.create('notes', '便签', content, {
|
|
icon: 'fa-sticky-note',
|
|
width: 700,
|
|
height: 500
|
|
});
|
|
|
|
setTimeout(() => {
|
|
renderNotesList();
|
|
initNotesEditor();
|
|
}, 100);
|
|
}
|
|
|
|
function renderNotesList() {
|
|
const list = document.getElementById('notes-list');
|
|
if (!list) return;
|
|
|
|
list.innerHTML = '';
|
|
|
|
if (state.notes.length === 0) {
|
|
list.innerHTML = '<div style="padding: 1rem; color: var(--text-muted); font-size: 0.85rem;">暂无便签</div>';
|
|
return;
|
|
}
|
|
|
|
state.notes.forEach((note, index) => {
|
|
const item = document.createElement('div');
|
|
item.className = 'note-item';
|
|
item.innerHTML = `
|
|
<div class="note-item-title">${note.title || '无标题'}</div>
|
|
<div class="note-item-preview">${note.content.substring(0, 30)}...</div>
|
|
<div class="note-item-date">${note.date}</div>
|
|
`;
|
|
item.addEventListener('click', () => loadNote(index));
|
|
list.appendChild(item);
|
|
});
|
|
}
|
|
|
|
function initNotesEditor() {
|
|
const titleInput = document.getElementById('note-title');
|
|
const contentArea = document.getElementById('note-content');
|
|
const newBtn = document.getElementById('new-note-btn');
|
|
const saveBtn = document.getElementById('save-note-btn');
|
|
|
|
const autoSave = () => {
|
|
const noteData = {
|
|
title: titleInput.value,
|
|
content: contentArea.value,
|
|
date: new Date().toLocaleString('zh-CN')
|
|
};
|
|
localStorage.setItem('cyberos_notes', JSON.stringify(state.notes));
|
|
};
|
|
|
|
let currentNoteIndex = -1;
|
|
|
|
window.loadNote = (index) => {
|
|
currentNoteIndex = index;
|
|
const note = state.notes[index];
|
|
if (titleInput) titleInput.value = note.title || '';
|
|
if (contentArea) contentArea.value = note.content || '';
|
|
};
|
|
|
|
window.saveNote = () => {
|
|
const title = titleInput ? titleInput.value : '';
|
|
const content = contentArea ? contentArea.value : '';
|
|
|
|
if (currentNoteIndex >= 0) {
|
|
state.notes[currentNoteIndex] = {
|
|
title,
|
|
content,
|
|
date: new Date().toLocaleString('zh-CN')
|
|
};
|
|
} else {
|
|
state.notes.unshift({
|
|
title,
|
|
content,
|
|
date: new Date().toLocaleString('zh-CN')
|
|
});
|
|
currentNoteIndex = 0;
|
|
}
|
|
|
|
localStorage.setItem('cyberos_notes', JSON.stringify(state.notes));
|
|
renderNotesList();
|
|
showNotification('便签', '便签已保存', 'success');
|
|
};
|
|
|
|
if (contentArea) {
|
|
contentArea.addEventListener('input', autoSave);
|
|
}
|
|
if (titleInput) {
|
|
titleInput.addEventListener('input', autoSave);
|
|
}
|
|
|
|
if (newBtn) {
|
|
newBtn.addEventListener('click', () => {
|
|
currentNoteIndex = -1;
|
|
if (titleInput) titleInput.value = '';
|
|
if (contentArea) contentArea.value = '';
|
|
});
|
|
}
|
|
}
|
|
|
|
// 系统监控
|
|
function openSystemMonitor() {
|
|
const content = `
|
|
<div class="system-monitor">
|
|
<div class="monitor-chart">
|
|
<h4><i class="fas fa-microchip icon"></i> CPU 使用率</h4>
|
|
<div class="chart-container">
|
|
<canvas id="cpu-chart"></canvas>
|
|
</div>
|
|
<div class="monitor-stats">
|
|
<div>
|
|
<div class="stat-value" id="cpu-value">45%</div>
|
|
<div class="stat-label">当前使用</div>
|
|
</div>
|
|
<div>
|
|
<div class="stat-value">2.4 GHz</div>
|
|
<div class="stat-label">频率</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="monitor-chart">
|
|
<h4><i class="fas fa-memory icon"></i> 内存使用</h4>
|
|
<div class="chart-container">
|
|
<canvas id="memory-chart"></canvas>
|
|
</div>
|
|
<div class="monitor-stats">
|
|
<div>
|
|
<div class="stat-value" id="memory-value">6.2 GB</div>
|
|
<div class="stat-label">已使用</div>
|
|
</div>
|
|
<div>
|
|
<div class="stat-value">16 GB</div>
|
|
<div class="stat-label">总容量</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="monitor-chart">
|
|
<h4><i class="fas fa-hdd icon"></i> 磁盘使用</h4>
|
|
<div class="chart-container">
|
|
<canvas id="disk-chart"></canvas>
|
|
</div>
|
|
<div class="monitor-stats">
|
|
<div>
|
|
<div class="stat-value" id="disk-value">256 GB</div>
|
|
<div class="stat-label">已使用</div>
|
|
</div>
|
|
<div>
|
|
<div class="stat-value">512 GB</div>
|
|
<div class="stat-label">总容量</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="monitor-chart">
|
|
<h4><i class="fas fa-network-wired icon"></i> 网络流量</h4>
|
|
<div class="chart-container">
|
|
<canvas id="network-chart"></canvas>
|
|
</div>
|
|
<div class="monitor-stats">
|
|
<div>
|
|
<div class="stat-value" id="network-value">15 MB/s</div>
|
|
<div class="stat-label">下载速度</div>
|
|
</div>
|
|
<div>
|
|
<div class="stat-value">3.2 MB/s</div>
|
|
<div class="stat-label">上传速度</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
const windowId = WindowManager.create('monitor', '系统监控', content, {
|
|
icon: 'fa-chart-line',
|
|
width: 800,
|
|
height: 550
|
|
});
|
|
|
|
setTimeout(() => {
|
|
initSystemMonitor();
|
|
}, 100);
|
|
}
|
|
|
|
function initSystemMonitor() {
|
|
const cpuCanvas = document.getElementById('cpu-chart');
|
|
const memoryCanvas = document.getElementById('memory-chart');
|
|
const diskCanvas = document.getElementById('disk-chart');
|
|
const networkCanvas = document.getElementById('network-chart');
|
|
|
|
if (!cpuCanvas) return;
|
|
|
|
const createChart = (canvas, color, label) => {
|
|
const ctx = canvas.getContext('2d');
|
|
return new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: Array(20).fill(''),
|
|
datasets: [{
|
|
data: Array(20).fill(50),
|
|
borderColor: color,
|
|
backgroundColor: color + '20',
|
|
borderWidth: 2,
|
|
fill: true,
|
|
tension: 0.4,
|
|
pointRadius: 0
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: { legend: { display: false } },
|
|
scales: {
|
|
x: { display: false },
|
|
y: {
|
|
min: 0,
|
|
max: 100,
|
|
grid: { color: 'rgba(255,255,255,0.1)' },
|
|
ticks: { color: 'rgba(255,255,255,0.5)' }
|
|
}
|
|
},
|
|
animation: { duration: 0 }
|
|
}
|
|
});
|
|
};
|
|
|
|
const cpuChart = createChart(cpuCanvas, '#00ffff', 'CPU');
|
|
const memoryChart = createChart(memoryCanvas, '#ff00ff', '内存');
|
|
const diskChart = createChart(diskCanvas, '#00ff88', '磁盘');
|
|
const networkChart = createChart(networkCanvas, '#ff6600', '网络');
|
|
|
|
const updateCharts = () => {
|
|
const cpuValue = Math.floor(Math.random() * 40) + 30;
|
|
const memoryValue = Math.floor(Math.random() * 20) + 35;
|
|
const diskValue = 50;
|
|
const networkValue = Math.floor(Math.random() * 30) + 10;
|
|
|
|
cpuChart.data.datasets[0].data.push(cpuValue);
|
|
cpuChart.data.datasets[0].data.shift();
|
|
cpuChart.update('none');
|
|
|
|
memoryChart.data.datasets[0].data.push(memoryValue);
|
|
memoryChart.data.datasets[0].data.shift();
|
|
memoryChart.update('none');
|
|
|
|
diskChart.data.datasets[0].data.push(diskValue);
|
|
diskChart.data.datasets[0].data.shift();
|
|
diskChart.update('none');
|
|
|
|
networkChart.data.datasets[0].data.push(networkValue);
|
|
networkChart.data.datasets[0].data.shift();
|
|
networkChart.update('none');
|
|
|
|
const cpuValueEl = document.getElementById('cpu-value');
|
|
const memoryValueEl = document.getElementById('memory-value');
|
|
const diskValueEl = document.getElementById('disk-value');
|
|
const networkValueEl = document.getElementById('network-value');
|
|
|
|
if (cpuValueEl) cpuValueEl.textContent = cpuValue + '%';
|
|
if (memoryValueEl) memoryValueEl.textContent = (memoryValue * 0.16).toFixed(1) + ' GB';
|
|
if (diskValueEl) diskValueEl.textContent = (diskValue * 0.512).toFixed(0) + ' GB';
|
|
if (networkValueEl) networkValueEl.textContent = (networkValue / 10).toFixed(1) + ' MB/s';
|
|
};
|
|
|
|
setInterval(updateCharts, 1000);
|
|
}
|
|
|
|
// ==================== 桌面初始化 ====================
|
|
function initDesktop() {
|
|
// 更新时钟
|
|
setInterval(updateClocks, 1000);
|
|
updateClocks();
|
|
|
|
// 初始化开始菜单应用
|
|
initStartMenuApps();
|
|
|
|
// 绑定桌面图标点击
|
|
document.querySelectorAll('.desktop-icon').forEach(icon => {
|
|
icon.addEventListener('dblclick', () => {
|
|
const app = icon.dataset.app;
|
|
openApp(app);
|
|
});
|
|
});
|
|
|
|
// 绑定开始按钮
|
|
document.getElementById('start-btn').addEventListener('click', toggleStartMenu);
|
|
|
|
// 绑定右键菜单
|
|
document.getElementById('desktop').addEventListener('contextmenu', (e) => {
|
|
e.preventDefault();
|
|
showContextMenu(e.clientX, e.clientY);
|
|
});
|
|
|
|
// 点击其他区域关闭菜单
|
|
document.addEventListener('click', (e) => {
|
|
if (!e.target.closest('#start-menu') && !e.target.closest('#start-btn')) {
|
|
document.getElementById('start-menu').classList.remove('active');
|
|
state.startMenuOpen = false;
|
|
}
|
|
if (!e.target.closest('#context-menu')) {
|
|
document.getElementById('context-menu').style.display = 'none';
|
|
state.contextMenuOpen = false;
|
|
}
|
|
});
|
|
|
|
// 绑定右键菜单操作
|
|
document.querySelectorAll('.context-item').forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const action = item.dataset.action;
|
|
handleContextAction(action);
|
|
document.getElementById('context-menu').style.display = 'none';
|
|
});
|
|
});
|
|
|
|
// 绑定电源按钮
|
|
document.getElementById('power-btn').addEventListener('click', () => {
|
|
if (confirm('确定要关机吗?')) {
|
|
document.body.innerHTML = '<div style="display: flex; justify-content: center; align-items: center; height: 100vh; background: #000; color: var(--neon-red); font-family: var(--font-mono); font-size: 2rem;">系统已关机</div>';
|
|
}
|
|
});
|
|
|
|
// 加载设置
|
|
loadSettings();
|
|
}
|
|
|
|
function updateClocks() {
|
|
const now = new Date();
|
|
|
|
document.getElementById('widget-time').textContent = formatTime(now);
|
|
document.getElementById('widget-date').textContent = formatDate(now).split(' ')[0];
|
|
document.getElementById('widget-month').textContent = (now.getMonth() + 1) + '月';
|
|
document.getElementById('widget-day').textContent = now.getDate();
|
|
document.getElementById('tray-time').textContent = formatTime(now).split(':').slice(0, 2).join(':');
|
|
document.getElementById('tray-date').textContent = formatShortDate(now);
|
|
}
|
|
|
|
function initStartMenuApps() {
|
|
const grid = document.getElementById('start-app-grid');
|
|
const apps = [
|
|
{ id: 'file-manager', name: '文件', icon: 'fa-folder' },
|
|
{ id: 'terminal', name: '终端', icon: 'fa-terminal' },
|
|
{ id: 'browser', name: '浏览器', icon: 'fa-globe' },
|
|
{ id: 'settings', name: '设置', icon: 'fa-cog' },
|
|
{ id: 'music', name: '音乐', icon: 'fa-music' },
|
|
{ id: 'notes', name: '便签', icon: 'fa-sticky-note' },
|
|
{ id: 'monitor', name: '监控', icon: 'fa-chart-line' }
|
|
];
|
|
|
|
apps.forEach(app => {
|
|
const item = document.createElement('div');
|
|
item.className = 'start-app-item';
|
|
item.innerHTML = `
|
|
<i class="fas ${app.icon} icon"></i>
|
|
<span class="name">${app.name}</span>
|
|
`;
|
|
item.addEventListener('click', () => {
|
|
openApp(app.id);
|
|
document.getElementById('start-menu').classList.remove('active');
|
|
state.startMenuOpen = false;
|
|
});
|
|
grid.appendChild(item);
|
|
});
|
|
}
|
|
|
|
function toggleStartMenu() {
|
|
const menu = document.getElementById('start-menu');
|
|
menu.classList.toggle('active');
|
|
state.startMenuOpen = menu.classList.contains('active');
|
|
}
|
|
|
|
function showContextMenu(x, y) {
|
|
const menu = document.getElementById('context-menu');
|
|
menu.style.left = x + 'px';
|
|
menu.style.top = y + 'px';
|
|
menu.style.display = 'flex';
|
|
state.contextMenuOpen = true;
|
|
}
|
|
|
|
function handleContextAction(action) {
|
|
switch (action) {
|
|
case 'refresh':
|
|
location.reload();
|
|
break;
|
|
case 'settings':
|
|
openSettings();
|
|
break;
|
|
case 'personalize':
|
|
openSettings();
|
|
break;
|
|
case 'terminal':
|
|
openTerminal();
|
|
break;
|
|
case 'about':
|
|
alert('CyberOS v2.0.0\n\n基于 Web 技术的赛博朋克风格操作系统模拟。\n\n技术栈: HTML5, CSS3, JavaScript ES6+\n依赖: Font Awesome, Chart.js, Anime.js');
|
|
break;
|
|
}
|
|
}
|
|
|
|
function openApp(appId) {
|
|
switch (appId) {
|
|
case 'file-manager':
|
|
openFileManager();
|
|
break;
|
|
case 'terminal':
|
|
openTerminal();
|
|
break;
|
|
case 'browser':
|
|
openBrowser();
|
|
break;
|
|
case 'settings':
|
|
openSettings();
|
|
break;
|
|
case 'music':
|
|
openMusic();
|
|
break;
|
|
case 'notes':
|
|
openNotes();
|
|
break;
|
|
case 'monitor':
|
|
openSystemMonitor();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ==================== 设置管理 ====================
|
|
function loadSettings() {
|
|
const saved = localStorage.getItem('cyberos_settings');
|
|
if (saved) {
|
|
state.settings = JSON.parse(saved);
|
|
}
|
|
}
|
|
|
|
function saveSettings() {
|
|
localStorage.setItem('cyberos_settings', JSON.stringify(state.settings));
|
|
}
|
|
|
|
// ==================== 启动 ====================
|
|
window.addEventListener('load', () => {
|
|
initBoot();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|