lyh-917 commited on
Commit
9a8061f
·
verified ·
1 Parent(s): 31bf5ac

Upload 18 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ static/logo_white.png filter=lfs diff=lfs merge=lfs -text
37
+ static/themes/cyberpunk/static/logo_white.png filter=lfs diff=lfs merge=lfs -text
static/.DS_Store ADDED
Binary file (6.15 kB). View file
 
static/logo.png ADDED
static/logo_white.png ADDED

Git LFS Details

  • SHA256: 12f4e878e80ae3d429573b9fd31001870ed62f41656b72b6d7f864f17fbe0fce
  • Pointer size: 131 Bytes
  • Size of remote file: 122 kB
static/main.example.js ADDED
@@ -0,0 +1,540 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let currentEventSource = null;
2
+
3
+ function createTask() {
4
+ const promptInput = document.getElementById('prompt-input');
5
+ const prompt = promptInput.value.trim();
6
+
7
+ if (!prompt) {
8
+ alert("Please enter a valid prompt");
9
+ promptInput.focus();
10
+ return;
11
+ }
12
+
13
+ if (currentEventSource) {
14
+ currentEventSource.close();
15
+ currentEventSource = null;
16
+ }
17
+
18
+ const container = document.getElementById('task-container');
19
+ container.innerHTML = '<div class="loading">Initializing task...</div>';
20
+ document.getElementById('input-container').classList.add('bottom');
21
+
22
+ fetch('/tasks', {
23
+ method: 'POST',
24
+ headers: {
25
+ 'Content-Type': 'application/json'
26
+ },
27
+ body: JSON.stringify({ prompt })
28
+ })
29
+ .then(response => {
30
+ if (!response.ok) {
31
+ return response.json().then(err => { throw new Error(err.detail || 'Request failed') });
32
+ }
33
+ return response.json();
34
+ })
35
+ .then(data => {
36
+ if (!data.task_id) {
37
+ throw new Error('Invalid task ID');
38
+ }
39
+ setupSSE(data.task_id);
40
+ loadHistory();
41
+ promptInput.value = '';
42
+ })
43
+ .catch(error => {
44
+ container.innerHTML = `<div class="error">Error: ${error.message}</div>`;
45
+ console.error('Failed to create task:', error);
46
+ });
47
+ }
48
+
49
+ function setupSSE(taskId) {
50
+ let retryCount = 0;
51
+ const maxRetries = 3;
52
+ const retryDelay = 2000;
53
+ let lastResultContent = '';
54
+
55
+ const container = document.getElementById('task-container');
56
+
57
+ function connect() {
58
+ const eventSource = new EventSource(`/tasks/${taskId}/events`);
59
+ currentEventSource = eventSource;
60
+
61
+ let heartbeatTimer = setInterval(() => {
62
+ container.innerHTML += '<div class="ping">·</div>';
63
+ }, 5000);
64
+
65
+ // Initial polling
66
+ fetch(`/tasks/${taskId}`)
67
+ .then(response => response.json())
68
+ .then(task => {
69
+ updateTaskStatus(task);
70
+ })
71
+ .catch(error => {
72
+ console.error('Initial status fetch failed:', error);
73
+ });
74
+
75
+ const handleEvent = (event, type) => {
76
+ clearInterval(heartbeatTimer);
77
+ try {
78
+ const data = JSON.parse(event.data);
79
+ container.querySelector('.loading')?.remove();
80
+ container.classList.add('active');
81
+
82
+ const stepContainer = ensureStepContainer(container);
83
+ const { formattedContent, timestamp } = formatStepContent(data, type);
84
+ const step = createStepElement(type, formattedContent, timestamp);
85
+
86
+ stepContainer.appendChild(step);
87
+ autoScroll(stepContainer);
88
+
89
+ fetch(`/tasks/${taskId}`)
90
+ .then(response => response.json())
91
+ .then(task => {
92
+ updateTaskStatus(task);
93
+ })
94
+ .catch(error => {
95
+ console.error('Status update failed:', error);
96
+ });
97
+ } catch (e) {
98
+ console.error(`Error handling ${type} event:`, e);
99
+ }
100
+ };
101
+
102
+ const eventTypes = ['think', 'tool', 'act', 'log', 'run', 'message'];
103
+ eventTypes.forEach(type => {
104
+ eventSource.addEventListener(type, (event) => handleEvent(event, type));
105
+ });
106
+
107
+ eventSource.addEventListener('complete', (event) => {
108
+ clearInterval(heartbeatTimer);
109
+ try {
110
+ const data = JSON.parse(event.data);
111
+ lastResultContent = data.result || '';
112
+
113
+ container.innerHTML += `
114
+ <div class="complete">
115
+ <div>✅ Task completed</div>
116
+ <pre>${lastResultContent}</pre>
117
+ </div>
118
+ `;
119
+
120
+ fetch(`/tasks/${taskId}`)
121
+ .then(response => response.json())
122
+ .then(task => {
123
+ updateTaskStatus(task);
124
+ })
125
+ .catch(error => {
126
+ console.error('Final status update failed:', error);
127
+ });
128
+
129
+ eventSource.close();
130
+ currentEventSource = null;
131
+ } catch (e) {
132
+ console.error('Error handling complete event:', e);
133
+ }
134
+ });
135
+
136
+ eventSource.addEventListener('error', (event) => {
137
+ clearInterval(heartbeatTimer);
138
+ try {
139
+ const data = JSON.parse(event.data);
140
+ container.innerHTML += `
141
+ <div class="error">
142
+ ❌ Error: ${data.message}
143
+ </div>
144
+ `;
145
+ eventSource.close();
146
+ currentEventSource = null;
147
+ } catch (e) {
148
+ console.error('Error handling failed:', e);
149
+ }
150
+ });
151
+
152
+ eventSource.onerror = (err) => {
153
+ if (eventSource.readyState === EventSource.CLOSED) return;
154
+
155
+ console.error('SSE connection error:', err);
156
+ clearInterval(heartbeatTimer);
157
+ eventSource.close();
158
+
159
+ fetch(`/tasks/${taskId}`)
160
+ .then(response => response.json())
161
+ .then(task => {
162
+ if (task.status === 'completed' || task.status === 'failed') {
163
+ updateTaskStatus(task);
164
+ if (task.status === 'completed') {
165
+ container.innerHTML += `
166
+ <div class="complete">
167
+ <div>✅ Task completed</div>
168
+ </div>
169
+ `;
170
+ } else {
171
+ container.innerHTML += `
172
+ <div class="error">
173
+ ❌ Error: ${task.error || 'Task failed'}
174
+ </div>
175
+ `;
176
+ }
177
+ } else if (retryCount < maxRetries) {
178
+ retryCount++;
179
+ container.innerHTML += `
180
+ <div class="warning">
181
+ ⚠ Connection lost, retrying in ${retryDelay/1000} seconds (${retryCount}/${maxRetries})...
182
+ </div>
183
+ `;
184
+ setTimeout(connect, retryDelay);
185
+ } else {
186
+ container.innerHTML += `
187
+ <div class="error">
188
+ ⚠ Connection lost, please try refreshing the page
189
+ </div>
190
+ `;
191
+ }
192
+ })
193
+ .catch(error => {
194
+ console.error('Task status check failed:', error);
195
+ if (retryCount < maxRetries) {
196
+ retryCount++;
197
+ setTimeout(connect, retryDelay);
198
+ }
199
+ });
200
+ };
201
+ }
202
+
203
+ connect();
204
+ }
205
+
206
+ function loadHistory() {
207
+ fetch('/tasks')
208
+ .then(response => {
209
+ if (!response.ok) {
210
+ return response.text().then(text => {
211
+ throw new Error(`request failure: ${response.status} - ${text.substring(0, 100)}`);
212
+ });
213
+ }
214
+ return response.json();
215
+ })
216
+ .then(tasks => {
217
+ const listContainer = document.getElementById('task-list');
218
+ listContainer.innerHTML = tasks.map(task => `
219
+ <div class="task-card" data-task-id="${task.id}">
220
+ <div>${task.prompt}</div>
221
+ <div class="task-meta">
222
+ ${new Date(task.created_at).toLocaleString()} -
223
+ <span class="status status-${task.status ? task.status.toLowerCase() : 'unknown'}">
224
+ ${task.status || 'Unknown state'}
225
+ </span>
226
+ </div>
227
+ </div>
228
+ `).join('');
229
+ })
230
+ .catch(error => {
231
+ console.error('Failed to load history records:', error);
232
+ const listContainer = document.getElementById('task-list');
233
+ listContainer.innerHTML = `<div class="error">Load Fail: ${error.message}</div>`;
234
+ });
235
+ }
236
+
237
+
238
+ function ensureStepContainer(container) {
239
+ let stepContainer = container.querySelector('.step-container');
240
+ if (!stepContainer) {
241
+ container.innerHTML = '<div class="step-container"></div>';
242
+ stepContainer = container.querySelector('.step-container');
243
+ }
244
+ return stepContainer;
245
+ }
246
+
247
+ function formatStepContent(data, eventType) {
248
+ return {
249
+ formattedContent: data.result,
250
+ timestamp: new Date().toLocaleTimeString()
251
+ };
252
+ }
253
+
254
+ function createStepElement(type, content, timestamp) {
255
+ const step = document.createElement('div');
256
+
257
+ // Executing step
258
+ const stepRegex = /Executing step (\d+)\/(\d+)/;
259
+ if (type === 'log' && stepRegex.test(content)) {
260
+ const match = content.match(stepRegex);
261
+ const currentStep = parseInt(match[1]);
262
+ const totalSteps = parseInt(match[2]);
263
+
264
+ step.className = 'step-divider';
265
+ step.innerHTML = `
266
+ <div class="step-circle">${currentStep}</div>
267
+ <div class="step-line"></div>
268
+ <div class="step-info">${currentStep}/${totalSteps}</div>
269
+ `;
270
+ } else if (type === 'act') {
271
+ // Check if it contains information about file saving
272
+ const saveRegex = /Content successfully saved to (.+)/;
273
+ const match = content.match(saveRegex);
274
+
275
+ step.className = `step-item ${type}`;
276
+
277
+ if (match && match[1]) {
278
+ const filePath = match[1].trim();
279
+ const fileName = filePath.split('/').pop();
280
+ const fileExtension = fileName.split('.').pop().toLowerCase();
281
+
282
+ // Handling different types of files
283
+ let fileInteractionHtml = '';
284
+
285
+ if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(fileExtension)) {
286
+ fileInteractionHtml = `
287
+ <div class="file-interaction image-preview">
288
+ <img src="${filePath}" alt="${fileName}" class="preview-image" onclick="showFullImage('${filePath}')">
289
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载图片</a>
290
+ </div>
291
+ `;
292
+ } else if (['mp3', 'wav', 'ogg'].includes(fileExtension)) {
293
+ fileInteractionHtml = `
294
+ <div class="file-interaction audio-player">
295
+ <audio controls src="${filePath}"></audio>
296
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载音频</a>
297
+ </div>
298
+ `;
299
+ } else if (['html', 'js', 'py'].includes(fileExtension)) {
300
+ fileInteractionHtml = `
301
+ <div class="file-interaction code-file">
302
+ <button onclick="simulateRunPython('${filePath}')" class="run-button">▶️ 模拟运行</button>
303
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载文件</a>
304
+ </div>
305
+ `;
306
+ } else {
307
+ fileInteractionHtml = `
308
+ <div class="file-interaction">
309
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载文件: ${fileName}</a>
310
+ </div>
311
+ `;
312
+ }
313
+
314
+ step.innerHTML = `
315
+ <div class="log-line">
316
+ <span class="log-prefix">${getEventIcon(type)} [${timestamp}] ${getEventLabel(type)}:</span>
317
+ <pre>${content}</pre>
318
+ ${fileInteractionHtml}
319
+ </div>
320
+ `;
321
+ } else {
322
+ step.innerHTML = `
323
+ <div class="log-line">
324
+ <span class="log-prefix">${getEventIcon(type)} [${timestamp}] ${getEventLabel(type)}:</span>
325
+ <pre>${content}</pre>
326
+ </div>
327
+ `;
328
+ }
329
+ } else {
330
+ step.className = `step-item ${type}`;
331
+ step.innerHTML = `
332
+ <div class="log-line">
333
+ <span class="log-prefix">${getEventIcon(type)} [${timestamp}] ${getEventLabel(type)}:</span>
334
+ <pre>${content}</pre>
335
+ </div>
336
+ `;
337
+ }
338
+ return step;
339
+ }
340
+
341
+ function autoScroll(element) {
342
+ requestAnimationFrame(() => {
343
+ element.scrollTo({
344
+ top: element.scrollHeight,
345
+ behavior: 'smooth'
346
+ });
347
+ });
348
+ setTimeout(() => {
349
+ element.scrollTop = element.scrollHeight;
350
+ }, 100);
351
+ }
352
+
353
+
354
+ function getEventIcon(eventType) {
355
+ const icons = {
356
+ 'think': '🤔',
357
+ 'tool': '🛠️',
358
+ 'act': '🚀',
359
+ 'result': '🏁',
360
+ 'error': '❌',
361
+ 'complete': '✅',
362
+ 'log': '📝',
363
+ 'run': '⚙️'
364
+ };
365
+ return icons[eventType] || 'ℹ️';
366
+ }
367
+
368
+ function getEventLabel(eventType) {
369
+ const labels = {
370
+ 'think': 'Thinking',
371
+ 'tool': 'Using Tool',
372
+ 'act': 'Action',
373
+ 'result': 'Result',
374
+ 'error': 'Error',
375
+ 'complete': 'Complete',
376
+ 'log': 'Log',
377
+ 'run': 'Running'
378
+ };
379
+ return labels[eventType] || 'Info';
380
+ }
381
+
382
+ function updateTaskStatus(task) {
383
+ const statusBar = document.getElementById('status-bar');
384
+ if (!statusBar) return;
385
+
386
+ if (task.status === 'completed') {
387
+ statusBar.innerHTML = `<span class="status-complete">✅ Task completed</span>`;
388
+
389
+ if (currentEventSource) {
390
+ currentEventSource.close();
391
+ currentEventSource = null;
392
+ }
393
+ } else if (task.status === 'failed') {
394
+ statusBar.innerHTML = `<span class="status-error">❌ Task failed: ${task.error || 'Unknown error'}</span>`;
395
+
396
+ if (currentEventSource) {
397
+ currentEventSource.close();
398
+ currentEventSource = null;
399
+ }
400
+ } else {
401
+ statusBar.innerHTML = `<span class="status-running">⚙️ Task running: ${task.status}</span>`;
402
+ }
403
+ }
404
+
405
+ // Display full screen image
406
+ function showFullImage(imageSrc) {
407
+ const modal = document.getElementById('image-modal');
408
+ if (!modal) {
409
+ const modalDiv = document.createElement('div');
410
+ modalDiv.id = 'image-modal';
411
+ modalDiv.className = 'image-modal';
412
+ modalDiv.innerHTML = `
413
+ <span class="close-modal">&times;</span>
414
+ <img src="${imageSrc}" class="modal-content" id="full-image">
415
+ `;
416
+ document.body.appendChild(modalDiv);
417
+
418
+ const closeBtn = modalDiv.querySelector('.close-modal');
419
+ closeBtn.addEventListener('click', () => {
420
+ modalDiv.classList.remove('active');
421
+ });
422
+
423
+ modalDiv.addEventListener('click', (e) => {
424
+ if (e.target === modalDiv) {
425
+ modalDiv.classList.remove('active');
426
+ }
427
+ });
428
+
429
+ setTimeout(() => modalDiv.classList.add('active'), 10);
430
+ } else {
431
+ document.getElementById('full-image').src = imageSrc;
432
+ modal.classList.add('active');
433
+ }
434
+ }
435
+
436
+ // Simulate running Python files
437
+ function simulateRunPython(filePath) {
438
+ let modal = document.getElementById('python-modal');
439
+ if (!modal) {
440
+ modal = document.createElement('div');
441
+ modal.id = 'python-modal';
442
+ modal.className = 'python-modal';
443
+ modal.innerHTML = `
444
+ <div class="python-console">
445
+ <div class="close-modal">&times;</div>
446
+ <div class="python-output">Loading Python file contents...</div>
447
+ </div>
448
+ `;
449
+ document.body.appendChild(modal);
450
+
451
+ const closeBtn = modal.querySelector('.close-modal');
452
+ closeBtn.addEventListener('click', () => {
453
+ modal.classList.remove('active');
454
+ });
455
+ }
456
+
457
+ modal.classList.add('active');
458
+
459
+ // Load Python file content
460
+ fetch(filePath)
461
+ .then(response => response.text())
462
+ .then(code => {
463
+ const outputDiv = modal.querySelector('.python-output');
464
+ outputDiv.innerHTML = '';
465
+
466
+ const codeElement = document.createElement('pre');
467
+ codeElement.textContent = code;
468
+ codeElement.style.marginBottom = '20px';
469
+ codeElement.style.padding = '10px';
470
+ codeElement.style.borderBottom = '1px solid #444';
471
+ outputDiv.appendChild(codeElement);
472
+
473
+ // Add simulation run results
474
+ const resultElement = document.createElement('div');
475
+ resultElement.innerHTML = `
476
+ <div style="color: #4CAF50; margin-top: 10px; margin-bottom: 10px;">
477
+ > Simulated operation output:</div>
478
+ <pre style="color: #f8f8f8;">
479
+ #This is the result of Python code simulation run
480
+ #The actual operational results may vary
481
+
482
+ # Running ${filePath.split('/').pop()}...
483
+ print("Hello from Python Simulated environment!")
484
+
485
+ # Code execution completed
486
+ </pre>
487
+ `;
488
+ outputDiv.appendChild(resultElement);
489
+ })
490
+ .catch(error => {
491
+ console.error('Error loading Python file:', error);
492
+ const outputDiv = modal.querySelector('.python-output');
493
+ outputDiv.innerHTML = `Error loading file: ${error.message}`;
494
+ });
495
+ }
496
+
497
+ document.addEventListener('DOMContentLoaded', () => {
498
+ loadHistory();
499
+
500
+ document.getElementById('prompt-input').addEventListener('keydown', (e) => {
501
+ if (e.key === 'Enter' && !e.shiftKey) {
502
+ e.preventDefault();
503
+ createTask();
504
+ }
505
+ });
506
+
507
+ const historyToggle = document.getElementById('history-toggle');
508
+ if (historyToggle) {
509
+ historyToggle.addEventListener('click', () => {
510
+ const historyPanel = document.getElementById('history-panel');
511
+ if (historyPanel) {
512
+ historyPanel.classList.toggle('open');
513
+ historyToggle.classList.toggle('active');
514
+ }
515
+ });
516
+ }
517
+
518
+ const clearButton = document.getElementById('clear-btn');
519
+ if (clearButton) {
520
+ clearButton.addEventListener('click', () => {
521
+ document.getElementById('prompt-input').value = '';
522
+ document.getElementById('prompt-input').focus();
523
+ });
524
+ }
525
+
526
+ // Add keyboard event listener to close modal boxes
527
+ document.addEventListener('keydown', (e) => {
528
+ if (e.key === 'Escape') {
529
+ const imageModal = document.getElementById('image-modal');
530
+ if (imageModal && imageModal.classList.contains('active')) {
531
+ imageModal.classList.remove('active');
532
+ }
533
+
534
+ const pythonModal = document.getElementById('python-modal');
535
+ if (pythonModal && pythonModal.classList.contains('active')) {
536
+ pythonModal.classList.remove('active');
537
+ }
538
+ }
539
+ });
540
+ });
static/main.js ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 加载页面控制函数
2
+ function initLoadingScreen() {
3
+ const loadingScreen = document.querySelector('.loading-screen');
4
+ const progressBar = document.querySelector('.progress-bar');
5
+ const progressText = document.querySelector('.progress-text .digital-glitch');
6
+ const loadingMessage = document.querySelector('.loading-message');
7
+
8
+ if (!loadingScreen || !progressBar || !progressText) return;
9
+
10
+ // 检查是否是从站内导航回来的
11
+ const referrer = document.referrer;
12
+ const currentHost = window.location.host;
13
+
14
+ // 如果是从同一站点的其他页面返回的,不显示加载动画
15
+ if (referrer && referrer.includes(currentHost) && !isPageReload()) {
16
+ loadingScreen.classList.add('hidden');
17
+ loadingScreen.style.display = 'none';
18
+ return;
19
+ }
20
+
21
+ const messages = [
22
+ "Initializing system components...",
23
+ "Connecting to neural network...",
24
+ "Loading AI modules...",
25
+ "Calibrating response patterns...",
26
+ "Starting quantum processors..."
27
+ ];
28
+
29
+ let progress = 0;
30
+ const totalDuration = 5000; // 5秒钟完成加载
31
+ const interval = 30; // 每30ms更新一次
32
+ const steps = totalDuration / interval;
33
+ const increment = 100 / steps;
34
+
35
+ // 随机更新消息
36
+ let messageIndex = 0;
37
+
38
+ const updateProgress = () => {
39
+ progress += increment;
40
+
41
+ // 添加一些随机性,模拟真实加载
42
+ const randomFactor = Math.random() * 0.5;
43
+ const adjustedProgress = Math.min(progress + randomFactor, 100);
44
+
45
+ // 更新进度条宽度
46
+ progressBar.style.width = `${adjustedProgress}%`;
47
+
48
+ // 更新进度文本
49
+ const displayProgress = Math.floor(adjustedProgress);
50
+ progressText.textContent = `${displayProgress}%`;
51
+
52
+ // 不同阶段显示不同消息
53
+ if (displayProgress > messageIndex * 25 && messageIndex < messages.length) {
54
+ loadingMessage.textContent = messages[messageIndex];
55
+ messageIndex++;
56
+
57
+ // 添加闪烁效果
58
+ loadingScreen.style.filter = 'brightness(1.2)';
59
+ setTimeout(() => {
60
+ loadingScreen.style.filter = 'brightness(1)';
61
+ }, 100);
62
+ }
63
+
64
+ // 模拟网络加载的变化
65
+ if (displayProgress >= 99.5) {
66
+ // 加载完成,隐藏加载屏幕
67
+ setTimeout(() => {
68
+ loadingScreen.classList.add('hidden');
69
+
70
+ // 完全隐藏后从DOM中移除
71
+ setTimeout(() => {
72
+ loadingScreen.style.display = 'none';
73
+ }, 500);
74
+ }, 200);
75
+ return;
76
+ }
77
+
78
+ // 添加随机故障效果
79
+ if (Math.random() < 0.1) {
80
+ createGlitchEffect();
81
+ }
82
+
83
+ requestAnimationFrame(updateProgress);
84
+ };
85
+
86
+ // 创建故障效果
87
+ const createGlitchEffect = () => {
88
+ // 屏幕抖动
89
+ loadingScreen.style.transform = `translate(${(Math.random() - 0.5) * 10}px, ${(Math.random() - 0.5) * 5}px)`;
90
+
91
+ // 随机调整颜色和不透明度
92
+ loadingScreen.style.filter = `hue-rotate(${Math.random() * 30}deg) brightness(${1 + Math.random() * 0.3})`;
93
+
94
+ // 恢复正常
95
+ setTimeout(() => {
96
+ loadingScreen.style.transform = 'translate(0, 0)';
97
+ loadingScreen.style.filter = 'none';
98
+ }, 100);
99
+ };
100
+
101
+ // 开始更新进度
102
+ setTimeout(() => {
103
+ updateProgress();
104
+ }, 300);
105
+ }
106
+
107
+ // 动态产生随机粒子
108
+ function createRandomParticle() {
109
+ const container = document.querySelector('.particle-container');
110
+
111
+ if (!container) return;
112
+
113
+ setInterval(() => {
114
+ const particle = document.createElement('div');
115
+ particle.className = 'particle';
116
+
117
+ // 随机位置
118
+ particle.style.left = `${Math.random() * 100}%`;
119
+ particle.style.top = '100%';
120
+
121
+ // 随机大小
122
+ const size = Math.random() * 2 + 1;
123
+ particle.style.width = `${size}px`;
124
+ particle.style.height = `${size}px`;
125
+
126
+ // 获取CSS变量
127
+ const styles = getComputedStyle(document.documentElement);
128
+ const colorOptions = [
129
+ styles.getPropertyValue('--accent-green').trim(),
130
+ styles.getPropertyValue('--accent-color-5').trim(),
131
+ styles.getPropertyValue('--accent-blue').trim(),
132
+ styles.getPropertyValue('--accent-color-1').trim()
133
+ ];
134
+
135
+ // 随机颜色
136
+ const randomColor = colorOptions[Math.floor(Math.random() * colorOptions.length)];
137
+ particle.style.backgroundColor = randomColor;
138
+ particle.style.boxShadow = `0 0 5px ${randomColor}`;
139
+
140
+ // 随机透明度
141
+ particle.style.opacity = (Math.random() * 0.5 + 0.3).toString();
142
+
143
+ // 添加到容器
144
+ container.appendChild(particle);
145
+
146
+ // 设置动画结束后移除元素
147
+ setTimeout(() => {
148
+ particle.remove();
149
+ }, 5000);
150
+ }, 600); // 每600ms创建一个新粒子
151
+ }
152
+
153
+ // 添加主题选项动画效果
154
+ function animateThemeOptions() {
155
+ const themeOptions = document.querySelectorAll('.theme-option');
156
+ themeOptions.forEach((option, index) => {
157
+ // 直接显示元素,不使用动画过渡
158
+ option.style.opacity = '1';
159
+ });
160
+ }
161
+
162
+ // 页面加载完成后初始化效果
163
+ document.addEventListener('DOMContentLoaded', function() {
164
+ // 初始化加载页面
165
+ initLoadingScreen();
166
+
167
+ // 初始化粒子效果
168
+ createRandomParticle();
169
+
170
+ // 初始化主题选项动画
171
+ animateThemeOptions();
172
+ });
173
+
174
+ // 仅用于开发环境 - 清除会话状态
175
+ function resetVisitState() {
176
+ // 清除会话状态相关变量
177
+ sessionStorage.clear();
178
+ console.log('Visit state has been reset. This will simulate a first-time visit on the next navigation.');
179
+ }
180
+
181
+ // 注释掉下面这行代码来禁用自动重置(仅开发环境使用)
182
+ // resetVisitState();
183
+
184
+ // 判断页面是否为刷新
185
+ function isPageReload() {
186
+ // 如果页面表现性能数据可用,检查导航类型
187
+ if (window.performance && window.performance.navigation) {
188
+ return window.performance.navigation.type === 1; // 1表示页面刷新
189
+ }
190
+
191
+ // 对较新的浏览器使用Navigation Timing API
192
+ if (window.performance && window.performance.getEntriesByType && window.performance.getEntriesByType('navigation').length) {
193
+ return window.performance.getEntriesByType('navigation')[0].type === 'reload';
194
+ }
195
+
196
+ // 无法确定时,假设不是刷新
197
+ return false;
198
+ }
static/style.css ADDED
@@ -0,0 +1,1379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --primary-color: #00ffcc;
3
+ --secondary-color: #0088ff;
4
+ --accent-color-1: #ff00aa;
5
+ --accent-color-2: #aa00ff;
6
+ --accent-color-3: #ffcc00;
7
+ --accent-color-4: #ff3300;
8
+ --accent-color-5: #00eeff;
9
+ --accent-blue: #3366ff;
10
+ --accent-purple: #9933ff;
11
+ --accent-pink: #ff66cc;
12
+ --accent-teal: #00ccaa;
13
+ --accent-green: #33ff99;
14
+ --accent-yellow: #ffcc33;
15
+ --text-color: #f8fafc;
16
+ --background-color: #000000;
17
+ --card-color: rgba(10, 30, 30, 0.5);
18
+ --border-color: #00aa99;
19
+ --highlight-color: #00ffaa;
20
+ --success-color: #10b981;
21
+ --warning-color: #f59e0b;
22
+ --error-color: #ef4444;
23
+ --info-color: #3b82f6;
24
+ --shadow-color: rgba(0, 0, 0, 0.5);
25
+ --glow-color: rgba(0, 255, 204, 0.5);
26
+ --transition-speed: 0.3s;
27
+ --font-primary: 'Outfit', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, sans-serif;
28
+ --font-mono: 'JetBrains Mono', 'Fira Code', 'Menlo', monospace;
29
+ }
30
+
31
+ * {
32
+ margin: 0;
33
+ padding: 0;
34
+ box-sizing: border-box;
35
+ font-family: var(--font-primary);
36
+ -webkit-font-smoothing: antialiased;
37
+ -moz-osx-font-smoothing: grayscale;
38
+ text-rendering: optimizeLegibility;
39
+ }
40
+
41
+ body {
42
+ background-color: var(--background-color);
43
+ color: var(--text-color);
44
+ height: 100vh;
45
+ overflow: hidden;
46
+ display: flex;
47
+ flex-direction: column;
48
+ position: relative;
49
+ font-feature-settings: "ss01", "ss02", "ss03", "cv01", "cv02", "cv03", "cv04";
50
+ -webkit-font-smoothing: antialiased;
51
+ -moz-osx-font-smoothing: grayscale;
52
+ text-rendering: optimizeLegibility;
53
+ font-synthesis: none;
54
+ }
55
+
56
+ body::before {
57
+ content: '';
58
+ position: absolute;
59
+ top: 0;
60
+ left: 0;
61
+ right: 0;
62
+ height: 100vh;
63
+ background: radial-gradient(circle at 50% 50%, rgba(0, 255, 204, 0.05), transparent 70%);
64
+ }
65
+
66
+ /* 首页主容器 */
67
+ .home-container {
68
+ display: flex;
69
+ flex-direction: column;
70
+ align-items: center;
71
+ justify-content: center;
72
+ min-height: 100vh;
73
+ width: 100%;
74
+ overflow: hidden;
75
+ position: relative;
76
+ z-index: 1;
77
+ max-height: 100vh;
78
+ }
79
+
80
+ .home-container::before {
81
+ content: '';
82
+ position: absolute;
83
+ top: -50%;
84
+ left: -50%;
85
+ right: -50%;
86
+ bottom: -50%;
87
+ background: radial-gradient(circle at center, rgba(139, 92, 246, 0.15), transparent 70%);
88
+ z-index: -1;
89
+ }
90
+
91
+ /* 英雄区域 */
92
+ .hero-section {
93
+ display: flex;
94
+ flex-direction: column;
95
+ align-items: center;
96
+ justify-content: center;
97
+ text-align: center;
98
+ min-height: 80vh;
99
+ width: 100%;
100
+ max-width: 1200px;
101
+ padding: 3rem 2rem;
102
+ position: relative;
103
+ z-index: 4;
104
+ isolation: isolate;
105
+ }
106
+
107
+ /* 标题样式 */
108
+ .title {
109
+ font-size: 7rem;
110
+ font-weight: 900;
111
+ margin-bottom: 2rem;
112
+ text-align: center;
113
+ letter-spacing: 5px;
114
+ position: relative;
115
+ z-index: 3;
116
+ color: #00ffcc;
117
+ text-shadow:
118
+ 0 0 10px rgba(0, 255, 204, 0.5),
119
+ 0 0 20px rgba(0, 238, 255, 0.3),
120
+ 0 0 30px rgba(0, 136, 255, 0.2),
121
+ 2px 2px 3px rgba(0, 0, 0, 0.6);
122
+ animation: neon-cyan-pulse 4s ease-in-out infinite alternate;
123
+ }
124
+
125
+ .title::before {
126
+ content: "";
127
+ position: absolute;
128
+ top: 0;
129
+ left: 0;
130
+ width: 100%;
131
+ height: 100%;
132
+ background: none;
133
+ z-index: -1;
134
+ }
135
+
136
+ .title::after {
137
+ content: "OPENMANUS";
138
+ position: absolute;
139
+ top: 1px;
140
+ left: 1px;
141
+ width: 100%;
142
+ height: 100%;
143
+ color: rgba(0, 255, 204, 0.15);
144
+ z-index: -1;
145
+ text-shadow: none;
146
+ filter: blur(5px);
147
+ }
148
+
149
+ @keyframes neon-cyan-pulse {
150
+ 0% {
151
+ text-shadow:
152
+ 0 0 8px rgba(0, 255, 204, 0.5),
153
+ 0 0 15px rgba(0, 238, 255, 0.3),
154
+ 0 0 20px rgba(0, 136, 255, 0.2),
155
+ 2px 2px 3px rgba(0, 0, 0, 0.6);
156
+ }
157
+ 100% {
158
+ text-shadow:
159
+ 0 0 10px rgba(0, 255, 204, 0.6),
160
+ 0 0 18px rgba(0, 238, 255, 0.4),
161
+ 0 0 25px rgba(0, 136, 255, 0.3),
162
+ 2px 2px 3px rgba(0, 0, 0, 0.6);
163
+ }
164
+ }
165
+
166
+ /* 副标题 */
167
+ .subtitle {
168
+ font-size: 2.2rem;
169
+ font-weight: 500;
170
+ margin-bottom: 2rem;
171
+ text-align: center;
172
+ position: relative;
173
+ background: linear-gradient(90deg, #ff3399, #9933ff);
174
+ -webkit-background-clip: text;
175
+ background-clip: text;
176
+ -webkit-text-fill-color: transparent;
177
+ text-shadow: none;
178
+ letter-spacing: 2px;
179
+ opacity: 1;
180
+ transform: translateZ(0);
181
+ -webkit-transform: translateZ(0);
182
+ -webkit-font-smoothing: antialiased;
183
+ -moz-osx-font-smoothing: grayscale;
184
+ backface-visibility: hidden;
185
+ z-index: 5;
186
+ isolation: isolate;
187
+ filter: drop-shadow(0 0 8px rgba(255, 51, 153, 0.3));
188
+ will-change: transform;
189
+ pointer-events: none;
190
+ }
191
+
192
+ /* 描述文本 */
193
+ .description {
194
+ font-size: 1.5rem;
195
+ line-height: 1.8;
196
+ margin-bottom: 2rem;
197
+ text-align: center;
198
+ max-width: 900px;
199
+ color: #a8b6c9;
200
+ padding: 0 2rem;
201
+ text-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
202
+ font-weight: 400;
203
+ letter-spacing: 0.8px;
204
+ opacity: 1;
205
+ transform: translateZ(0);
206
+ -webkit-transform: translateZ(0);
207
+ -webkit-font-smoothing: subpixel-antialiased;
208
+ backface-visibility: hidden;
209
+ position: relative;
210
+ z-index: 3;
211
+ isolation: isolate;
212
+ mix-blend-mode: normal;
213
+ }
214
+
215
+ /* 描述文本中的强调部分 */
216
+ .description span:not(.powered-text) {
217
+ position: relative;
218
+ display: inline-block;
219
+ background: linear-gradient(90deg, var(--accent-color-4), var(--accent-color-3));
220
+ -webkit-background-clip: text;
221
+ background-clip: text;
222
+ color: transparent;
223
+ padding: 0 5px;
224
+ font-weight: 600;
225
+ text-shadow: 0 0 6px rgba(255, 153, 0, 0.4);
226
+ transform: translateZ(0);
227
+ -webkit-transform: translateZ(0);
228
+ -webkit-font-smoothing: subpixel-antialiased;
229
+ }
230
+
231
+ /* Powered by 文本专用样式 */
232
+ .powered-text {
233
+ font-size: 1.5rem;
234
+ color: #8c9cb0;
235
+ letter-spacing: 0.3px;
236
+ font-weight: 400;
237
+ background: none;
238
+ -webkit-background-clip: unset;
239
+ background-clip: unset;
240
+ -webkit-text-fill-color: #8c9cb0;
241
+ padding: 0;
242
+ }
243
+
244
+ /* 描述文本中的强调部分 */
245
+ .description span:nth-of-type(2) {
246
+ background: linear-gradient(90deg, var(--accent-color-1), var(--accent-pink));
247
+ -webkit-background-clip: text;
248
+ background-clip: text;
249
+ text-shadow: 0 0 8px rgba(255, 0, 170, 0.4);
250
+ }
251
+
252
+ .description span:nth-of-type(4) {
253
+ background: linear-gradient(90deg, var(--accent-green), var(--accent-teal));
254
+ -webkit-background-clip: text;
255
+ background-clip: text;
256
+ text-shadow: 0 0 8px rgba(0, 204, 170, 0.4);
257
+ }
258
+
259
+ /* CTA按钮 */
260
+ .cta-button {
261
+ display: inline-flex;
262
+ align-items: center;
263
+ justify-content: center;
264
+ padding: 8px 24px;
265
+ font-size: 0.9rem;
266
+ font-weight: 600;
267
+ color: white;
268
+ background: linear-gradient(45deg, var(--accent-teal), var(--accent-color-2));
269
+ border: none;
270
+ border-radius: 6px;
271
+ cursor: pointer;
272
+ transition: all 0.4s ease;
273
+ box-shadow: 0 0 20px rgba(170, 0, 255, 0.4), 0 0 0 1px rgba(0, 204, 170, 0.1) inset;
274
+ position: relative;
275
+ overflow: hidden;
276
+ margin-top: 0.6rem;
277
+ letter-spacing: 1.5px;
278
+ text-transform: uppercase;
279
+ text-decoration: none;
280
+ }
281
+
282
+ .cta-button::before {
283
+ content: '';
284
+ position: absolute;
285
+ top: -50%;
286
+ left: -50%;
287
+ width: 200%;
288
+ height: 200%;
289
+ background: linear-gradient(
290
+ to right,
291
+ transparent,
292
+ rgba(255, 255, 255, 0.4),
293
+ transparent
294
+ );
295
+ transform: rotate(45deg);
296
+ z-index: 1;
297
+ }
298
+
299
+ .cta-button::after {
300
+ content: '';
301
+ position: absolute;
302
+ inset: -1px;
303
+ border-radius: 12px;
304
+ padding: 1px;
305
+ background: linear-gradient(135deg, var(--accent-color-5), var(--accent-blue), var(--accent-purple));
306
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
307
+ -webkit-mask-composite: xor;
308
+ mask-composite: exclude;
309
+ z-index: -1;
310
+ opacity: 0.6;
311
+ transition: opacity 0.4s ease;
312
+ }
313
+
314
+ .cta-button:hover {
315
+ transform: translateY(-5px);
316
+ box-shadow: 0 10px 30px rgba(170, 0, 255, 0.5), 0 0 0 1px rgba(0, 204, 170, 0.2) inset;
317
+ background: linear-gradient(45deg, var(--accent-color-1), var(--accent-blue));
318
+ }
319
+
320
+ .cta-button:hover::after {
321
+ opacity: 1;
322
+ }
323
+
324
+ .arrow-icon {
325
+ margin-left: 8px;
326
+ font-size: 0.9rem;
327
+ }
328
+
329
+ /* 主题选择器 */
330
+ .theme-selector {
331
+ width: 100%;
332
+ max-width: 680px;
333
+ margin: 2rem auto;
334
+ }
335
+
336
+ .theme-label {
337
+ font-size: 1.2rem;
338
+ font-weight: 500;
339
+ margin-bottom: 1rem;
340
+ text-align: center;
341
+ color: var(--accent-color-5);
342
+ text-transform: uppercase;
343
+ letter-spacing: 1.2px;
344
+ position: relative;
345
+ text-shadow: 0 0 3px rgba(0, 238, 255, 0.3);
346
+ }
347
+
348
+ .theme-options {
349
+ display: flex;
350
+ justify-content: center;
351
+ flex-wrap: wrap;
352
+ gap: 1.5rem;
353
+ margin-top: 1rem;
354
+ margin-bottom: 1rem;
355
+ }
356
+
357
+ .theme-options .theme-option {
358
+ width: 80px !important;
359
+ height: 80px !important;
360
+ display: flex;
361
+ flex-direction: column;
362
+ align-items: center;
363
+ justify-content: center;
364
+ background: linear-gradient(180deg, rgba(10, 30, 50, 0.9), rgba(5, 15, 35, 0.8));
365
+ border-radius: 12px;
366
+ border: 1px solid rgba(0, 238, 255, 0.3);
367
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3), 0 0 5px rgba(0, 238, 255, 0.2);
368
+ padding: 0.5rem;
369
+ position: relative;
370
+ cursor: pointer;
371
+ transition: all 0.3s ease;
372
+ opacity: 1;
373
+ overflow: visible;
374
+ text-decoration: none !important;
375
+ }
376
+
377
+ .theme-options .theme-option .theme-icon-container {
378
+ width: 36px !important;
379
+ height: 36px !important;
380
+ margin-bottom: 0.5rem;
381
+ background: linear-gradient(135deg, rgba(0, 30, 40, 0.95), rgba(0, 15, 30, 0.95));
382
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3),
383
+ inset 0 0 2px rgba(0, 238, 255, 0.2);
384
+ border-radius: 50%;
385
+ display: flex;
386
+ align-items: center;
387
+ justify-content: center;
388
+ position: relative;
389
+ overflow: hidden;
390
+ }
391
+
392
+ .theme-options .theme-option .theme-icon {
393
+ font-size: 1.2rem !important;
394
+ filter: drop-shadow(0 0 2px rgba(51, 255, 153, 0.3));
395
+ color: var(--accent-green);
396
+ z-index: 2;
397
+ }
398
+
399
+ .theme-options .theme-option .theme-name {
400
+ font-size: 0.9rem !important;
401
+ font-weight: 500;
402
+ color: var(--primary-color);
403
+ letter-spacing: 0.5px;
404
+ margin-top: 0.3rem;
405
+ text-align: center;
406
+ white-space: nowrap;
407
+ width: 100%;
408
+ overflow: hidden;
409
+ text-overflow: ellipsis;
410
+ }
411
+
412
+ .theme-options .theme-option:hover,
413
+ .theme-options .theme-option:active {
414
+ transform: translateY(-4px) scale(1.05);
415
+ border-color: rgba(0, 255, 204, 0.5);
416
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4), 0 0 10px rgba(0, 255, 204, 0.3);
417
+ z-index: 5;
418
+ }
419
+
420
+ /* CTA按钮 */
421
+ .hero-section .cta-button {
422
+ display: inline-flex;
423
+ align-items: center;
424
+ justify-content: center;
425
+ padding: 12px 36px !important;
426
+ font-size: 1.2rem !important;
427
+ font-weight: 600;
428
+ color: white;
429
+ background: linear-gradient(45deg, var(--accent-teal), var(--accent-color-2));
430
+ border: none;
431
+ border-radius: 12px;
432
+ cursor: pointer;
433
+ transition: all 0.4s ease;
434
+ box-shadow: 0 0 20px rgba(170, 0, 255, 0.4), 0 0 0 1px rgba(0, 204, 170, 0.1) inset;
435
+ position: relative;
436
+ overflow: hidden;
437
+ margin-top: 2rem !important;
438
+ letter-spacing: 2px;
439
+ text-transform: uppercase;
440
+ text-decoration: none;
441
+ min-width: 200px;
442
+ max-width: 280px;
443
+ }
444
+
445
+ .hero-section .cta-button .arrow-icon {
446
+ margin-left: 12px;
447
+ font-size: 1.2rem;
448
+ }
449
+
450
+ /* 粒子效果 */
451
+ .particle-container {
452
+ position: absolute;
453
+ top: 0;
454
+ left: 0;
455
+ width: 100%;
456
+ height: 100%;
457
+ overflow: hidden;
458
+ z-index: -1;
459
+ }
460
+
461
+ .particle {
462
+ position: absolute;
463
+ width: 2px;
464
+ height: 2px;
465
+ background-color: var(--accent-green);
466
+ border-radius: 50%;
467
+ opacity: 0;
468
+ animation: particle-animation 8s linear infinite;
469
+ box-shadow: 0 0 5px currentColor;
470
+ z-index: -1;
471
+ }
472
+
473
+ .particle:nth-child(1) { left: 10%; top: 20%; animation-delay: 0s; background-color: var(--accent-green); box-shadow: 0 0 8px var(--accent-green); }
474
+ .particle:nth-child(2) { left: 20%; top: 80%; animation-delay: 1s; background-color: var(--accent-blue); box-shadow: 0 0 8px var(--accent-blue); }
475
+ .particle:nth-child(3) { left: 30%; top: 40%; animation-delay: 2s; background-color: var(--accent-color-5); box-shadow: 0 0 8px var(--accent-color-5); }
476
+ .particle:nth-child(4) { left: 40%; top: 60%; animation-delay: 3s; background-color: var(--accent-teal); box-shadow: 0 0 8px var(--accent-teal); }
477
+ .particle:nth-child(5) { left: 50%; top: 20%; animation-delay: 4s; background-color: var(--accent-color-1); box-shadow: 0 0 8px var(--accent-color-1); }
478
+ .particle:nth-child(6) { left: 60%; top: 70%; animation-delay: 5s; background-color: var(--accent-purple); box-shadow: 0 0 8px var(--accent-purple); }
479
+ .particle:nth-child(7) { left: 70%; top: 30%; animation-delay: 6s; background-color: var(--accent-color-2); box-shadow: 0 0 8px var(--accent-color-2); }
480
+ .particle:nth-child(8) { left: 80%; top: 50%; animation-delay: 7s; background-color: var(--accent-yellow); box-shadow: 0 0 8px var(--accent-yellow); }
481
+ .particle:nth-child(9) { left: 90%; top: 10%; animation-delay: 8s; background-color: var(--accent-pink); box-shadow: 0 0 8px var(--accent-pink); }
482
+ .particle:nth-child(10) { left: 5%; top: 70%; animation-delay: 9s; background-color: var(--accent-color-3); box-shadow: 0 0 8px var(--accent-color-3); }
483
+ .particle:nth-child(11) { left: 15%; top: 10%; animation-delay: 10s; background-color: var(--accent-color-4); box-shadow: 0 0 8px var(--accent-color-4); }
484
+ .particle:nth-child(12) { left: 25%; top: 90%; animation-delay: 11s; background-color: var(--accent-teal); box-shadow: 0 0 8px var(--accent-teal); }
485
+
486
+ @keyframes particle-animation {
487
+ 0% {
488
+ transform: translateY(0) scale(0);
489
+ opacity: 0;
490
+ filter: brightness(0.5);
491
+ }
492
+ 10% {
493
+ opacity: 0.8;
494
+ filter: brightness(1);
495
+ }
496
+ 80% {
497
+ opacity: 0.8;
498
+ filter: brightness(1.2);
499
+ }
500
+ 100% {
501
+ transform: translateY(-100vh) scale(1.2);
502
+ opacity: 0;
503
+ filter: brightness(0.5);
504
+ }
505
+ }
506
+
507
+ /* 电路效果 */
508
+ .tech-circuit {
509
+ position: absolute;
510
+ top: 0;
511
+ left: 0;
512
+ width: 100%;
513
+ height: 100%;
514
+ pointer-events: none;
515
+ z-index: -1;
516
+ opacity: 0.5;
517
+ overflow: hidden;
518
+ will-change: opacity;
519
+ transform: translateZ(0);
520
+ }
521
+
522
+ .circuit-line {
523
+ position: absolute;
524
+ background: linear-gradient(90deg, transparent, var(--accent-green), transparent);
525
+ height: 2px;
526
+ width: 100%;
527
+ opacity: 0.3;
528
+ animation: circuit-pulse 4s infinite ease-in-out;
529
+ filter: drop-shadow(0 0 5px var(--accent-green));
530
+ transform: translateZ(0);
531
+ will-change: opacity, filter;
532
+ pointer-events: none;
533
+ }
534
+
535
+ .circuit-line:nth-child(1) { top: 15%; animation-delay: 0s; background: linear-gradient(90deg, transparent, var(--accent-green), transparent); }
536
+ .circuit-line:nth-child(2) { top: 35%; animation-delay: 1s; background: linear-gradient(90deg, transparent, var(--accent-color-5), transparent); }
537
+ .circuit-line:nth-child(3) { top: 55%; animation-delay: 2s; background: linear-gradient(90deg, transparent, var(--accent-purple), transparent); }
538
+ .circuit-line:nth-child(4) { top: 75%; animation-delay: 3s; background: linear-gradient(90deg, transparent, var(--accent-color-1), transparent); }
539
+
540
+ .circuit-vertical {
541
+ position: absolute;
542
+ background: linear-gradient(180deg, transparent, var(--accent-teal), transparent);
543
+ width: 2px;
544
+ height: 100%;
545
+ opacity: 0.3;
546
+ animation: circuit-pulse 4s infinite ease-in-out;
547
+ filter: drop-shadow(0 0 5px var(--accent-teal));
548
+ transform: translateZ(0);
549
+ will-change: opacity, filter;
550
+ pointer-events: none;
551
+ }
552
+
553
+ .circuit-vertical:nth-child(5) { left: 20%; animation-delay: 0.5s; background: linear-gradient(180deg, transparent, var(--accent-color-5), transparent); }
554
+ .circuit-vertical:nth-child(6) { left: 40%; animation-delay: 1.5s; background: linear-gradient(180deg, transparent, var(--accent-color-5), transparent); }
555
+ .circuit-vertical:nth-child(7) { left: 60%; animation-delay: 2.5s; background: linear-gradient(180deg, transparent, var(--accent-blue), transparent); }
556
+ .circuit-vertical:nth-child(8) { left: 80%; animation-delay: 3.5s; background: linear-gradient(180deg, transparent, var(--accent-pink), transparent); }
557
+
558
+ .circuit-node {
559
+ position: absolute;
560
+ width: 6px;
561
+ height: 6px;
562
+ background-color: var(--accent-green);
563
+ border-radius: 50%;
564
+ opacity: 0.4;
565
+ box-shadow: 0 0 12px var(--accent-green);
566
+ animation: node-pulse 4s infinite;
567
+ transform: translateZ(0);
568
+ will-change: transform, opacity;
569
+ pointer-events: none;
570
+ }
571
+
572
+ .circuit-node:nth-child(9) { top: 15%; left: 20%; animation-delay: 0s; background-color: var(--accent-green); box-shadow: 0 0 15px var(--accent-green); }
573
+ .circuit-node:nth-child(10) { top: 35%; left: 40%; animation-delay: 1s; background-color: var(--accent-color-5); box-shadow: 0 0 15px var(--accent-color-5); }
574
+ .circuit-node:nth-child(11) { top: 55%; left: 60%; animation-delay: 2s; background-color: var(--accent-purple); box-shadow: 0 0 15px var(--accent-purple); }
575
+ .circuit-node:nth-child(12) { top: 75%; left: 80%; animation-delay: 3s; background-color: var(--accent-color-1); box-shadow: 0 0 15px var(--accent-color-1); }
576
+
577
+ .circuit-node-small {
578
+ width: 4px;
579
+ height: 4px;
580
+ animation: node-pulse-small 3s infinite alternate;
581
+ }
582
+
583
+ .circuit-node-small:nth-child(13) { top: 25%; left: 30%; animation-delay: 0.7s; background-color: var(--accent-yellow); box-shadow: 0 0 10px var(--accent-yellow); }
584
+ .circuit-node-small:nth-child(14) { top: 45%; left: 10%; animation-delay: 1.2s; background-color: var(--accent-color-5); box-shadow: 0 0 10px var(--accent-color-5); }
585
+ .circuit-node-small:nth-child(15) { top: 65%; left: 50%; animation-delay: 1.7s; background-color: var(--accent-teal); box-shadow: 0 0 10px var(--accent-teal); }
586
+ .circuit-node-small:nth-child(16) { top: 85%; left: 70%; animation-delay: 2.2s; background-color: var(--accent-blue); box-shadow: 0 0 10px var(--accent-blue); }
587
+ .circuit-node-small:nth-child(17) { top: 10%; left: 75%; animation-delay: 2.7s; background-color: var(--accent-purple); box-shadow: 0 0 10px var(--accent-purple); }
588
+ .circuit-node-small:nth-child(18) { top: 60%; left: 90%; animation-delay: 3.2s; background-color: var(--accent-color-1); box-shadow: 0 0 10px var(--accent-color-1); }
589
+
590
+ .circuit-diagonal {
591
+ position: absolute;
592
+ width: 150%;
593
+ height: 1px;
594
+ top: 50%;
595
+ left: -25%;
596
+ transform: rotate(15deg);
597
+ background: linear-gradient(90deg, transparent, var(--accent-color-3), transparent);
598
+ opacity: 0.25;
599
+ animation: circuit-pulse 5s infinite ease-in-out;
600
+ filter: drop-shadow(0 0 3px #00eeff);
601
+ transform: translateZ(0);
602
+ will-change: opacity, filter;
603
+ pointer-events: none;
604
+ }
605
+
606
+ .circuit-diagonal:nth-child(19) { top: 30%; animation-delay: 0.5s; background: linear-gradient(90deg, transparent, var(--accent-color-3), transparent); }
607
+ .circuit-diagonal:nth-child(20) { top: 70%; animation-delay: 2.5s; background: linear-gradient(90deg, transparent, var(--accent-color-4), transparent); }
608
+
609
+ .circuit-diagonal-reverse {
610
+ transform: rotate(-15deg);
611
+ }
612
+
613
+ .circuit-diagonal-reverse:nth-child(21) { top: 40%; animation-delay: 1.5s; background: linear-gradient(90deg, transparent, var(--accent-pink), transparent); }
614
+ .circuit-diagonal-reverse:nth-child(22) { top: 80%; animation-delay: 3.5s; background: linear-gradient(90deg, transparent, var(--accent-color-2), transparent); }
615
+
616
+ /* 优化动画性能 */
617
+ @keyframes circuit-pulse {
618
+ 0%, 100% {
619
+ opacity: 0.2;
620
+ filter: drop-shadow(0 0 1px currentColor);
621
+ }
622
+ 50% {
623
+ opacity: 0.4;
624
+ filter: drop-shadow(0 0 4px currentColor);
625
+ }
626
+ }
627
+
628
+ @keyframes node-pulse {
629
+ 0%, 100% {
630
+ opacity: 0.3;
631
+ transform: scale(1) translateZ(0);
632
+ filter: brightness(0.8);
633
+ }
634
+ 50% {
635
+ opacity: 0.5;
636
+ transform: scale(1.2) translateZ(0);
637
+ filter: brightness(1.2);
638
+ }
639
+ }
640
+
641
+ @keyframes node-pulse-small {
642
+ 0%, 100% {
643
+ opacity: 0.2;
644
+ transform: scale(1) translateZ(0);
645
+ }
646
+ 50% {
647
+ opacity: 0.4;
648
+ transform: scale(1.2) translateZ(0);
649
+ }
650
+ }
651
+
652
+ /* 响应式设计 - 调整缩小后的尺寸 */
653
+ @media screen and (max-width: 1200px) {
654
+ .title {
655
+ font-size: 5rem;
656
+ }
657
+ .hero-section {
658
+ min-height: 100vh;
659
+ padding: 2rem 1rem;
660
+ }
661
+ }
662
+
663
+ @media screen and (max-width: 768px) {
664
+ .title {
665
+ font-size: 4rem;
666
+ margin-bottom: 1rem;
667
+ letter-spacing: 2px;
668
+ }
669
+ .subtitle {
670
+ font-size: 1.5rem;
671
+ margin-bottom: 1rem;
672
+ }
673
+ .description {
674
+ font-size: 1rem;
675
+ margin-bottom: 1.5rem;
676
+ line-height: 1.6;
677
+ padding: 0 1rem;
678
+ }
679
+ .cta-button {
680
+ padding: 10px 24px;
681
+ font-size: 0.9rem;
682
+ }
683
+ .theme-selector {
684
+ margin: 1.5rem auto;
685
+ max-width: 90%;
686
+ }
687
+ .theme-options {
688
+ gap: 1rem;
689
+ justify-content: center;
690
+ }
691
+ .hero-section {
692
+ justify-content: center;
693
+ align-items: center;
694
+ display: flex;
695
+ flex-direction: column;
696
+ }
697
+ .theme-options .theme-option {
698
+ width: 70px !important;
699
+ height: 70px !important;
700
+ margin: 0 5px;
701
+ border: 1px solid rgba(0, 238, 255, 0.4);
702
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 6px rgba(0, 238, 255, 0.3);
703
+ }
704
+
705
+ .theme-options .theme-option .theme-icon-container {
706
+ width: 30px !important;
707
+ height: 30px !important;
708
+ }
709
+
710
+ .theme-options .theme-option .theme-name {
711
+ font-size: 0.75rem !important;
712
+ }
713
+
714
+ .hero-section .cta-button {
715
+ padding: 10px 24px !important;
716
+ font-size: 1rem !important;
717
+ margin-top: 1.5rem !important;
718
+ }
719
+
720
+ .github-link {
721
+ width: 38px;
722
+ height: 38px;
723
+ font-size: 1.3rem;
724
+ top: 15px;
725
+ right: 15px;
726
+ }
727
+ }
728
+
729
+ @media screen and (max-width: 480px) {
730
+ .title {
731
+ font-size: 3.2rem;
732
+ margin-bottom: 0.8rem;
733
+ letter-spacing: 1.5px;
734
+ }
735
+ .subtitle {
736
+ font-size: 1.2rem;
737
+ margin-bottom: 1rem;
738
+ }
739
+ .description {
740
+ font-size: 0.9rem;
741
+ margin-bottom: 1.5rem;
742
+ padding: 0 0.5rem;
743
+ }
744
+ .cta-button {
745
+ padding: 8px 20px;
746
+ font-size: 0.85rem;
747
+ }
748
+ .hero-section {
749
+ min-height: 100vh;
750
+ padding: 1.5rem 0.5rem;
751
+ justify-content: center;
752
+ display: flex;
753
+ flex-direction: column;
754
+ }
755
+ .theme-selector {
756
+ margin: 1rem auto;
757
+ padding: 0.5rem;
758
+ border-radius: 12px;
759
+ background: rgba(5, 15, 25, 0.3);
760
+ border: 1px solid rgba(0, 238, 255, 0.15);
761
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
762
+ }
763
+ .theme-options {
764
+ gap: 1rem;
765
+ padding: 0.5rem;
766
+ }
767
+ .theme-options .theme-option {
768
+ width: 65px !important;
769
+ height: 65px !important;
770
+ margin: 0 4px 8px;
771
+ border: 1px solid rgba(0, 238, 255, 0.5);
772
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), 0 0 8px rgba(0, 238, 255, 0.3);
773
+ background: linear-gradient(180deg, rgba(15, 35, 55, 0.95), rgba(8, 20, 40, 0.9));
774
+ }
775
+
776
+ .theme-options .theme-option .theme-icon-container {
777
+ width: 28px !important;
778
+ height: 28px !important;
779
+ margin-bottom: 0.4rem;
780
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3),
781
+ inset 0 0 4px rgba(0, 238, 255, 0.3);
782
+ }
783
+
784
+ .theme-options .theme-option .theme-name {
785
+ font-size: 0.7rem !important;
786
+ margin-top: 0.3rem;
787
+ text-shadow: 0 0 4px rgba(0, 255, 204, 0.4);
788
+ }
789
+
790
+ .theme-label {
791
+ margin-bottom: 0.6rem;
792
+ font-size: 1.1rem;
793
+ text-shadow: 0 0 6px rgba(0, 238, 255, 0.5);
794
+ }
795
+
796
+ .tech-circuit, .particle-container {
797
+ opacity: 0.6;
798
+ }
799
+
800
+ .hero-section .cta-button {
801
+ padding: 8px 18px !important;
802
+ font-size: 0.9rem !important;
803
+ min-width: 160px;
804
+ margin-top: 1rem !important;
805
+ }
806
+
807
+ .github-link {
808
+ width: 34px;
809
+ height: 34px;
810
+ font-size: 1.2rem;
811
+ top: 12px;
812
+ right: 12px;
813
+ }
814
+ }
815
+
816
+ @media screen and (max-width: 360px) {
817
+ .title {
818
+ font-size: 2.8rem;
819
+ margin-bottom: 0.7rem;
820
+ }
821
+ .subtitle {
822
+ font-size: 1rem;
823
+ margin-bottom: 0.7rem;
824
+ }
825
+ .description {
826
+ font-size: 0.8rem;
827
+ margin-bottom: 1.2rem;
828
+ }
829
+ .cta-button {
830
+ padding: 7px 16px;
831
+ font-size: 0.8rem;
832
+ }
833
+ .theme-options {
834
+ gap: 0.5rem;
835
+ }
836
+ .theme-options .theme-option {
837
+ width: 56px !important;
838
+ height: 56px !important;
839
+ margin: 0 3px 6px;
840
+ }
841
+
842
+ .theme-options .theme-option .theme-icon-container {
843
+ width: 24px !important;
844
+ height: 24px !important;
845
+ }
846
+
847
+ .theme-options .theme-option .theme-name {
848
+ font-size: 0.65rem !important;
849
+ }
850
+
851
+ .hero-section .cta-button {
852
+ padding: 7px 16px !important;
853
+ font-size: 0.85rem !important;
854
+ min-width: 140px;
855
+ }
856
+
857
+ .github-link {
858
+ width: 30px;
859
+ height: 30px;
860
+ font-size: 1rem;
861
+ top: 10px;
862
+ right: 10px;
863
+ }
864
+ }
865
+
866
+ @media screen and (max-height: 700px) {
867
+ .hero-section {
868
+ min-height: auto;
869
+ padding: 1rem 1rem;
870
+ }
871
+ .description {
872
+ margin-bottom: 1rem;
873
+ max-width: 600px;
874
+ }
875
+ .title {
876
+ margin-bottom: 0.5rem;
877
+ }
878
+ .subtitle {
879
+ margin-bottom: 0.5rem;
880
+ }
881
+ }
882
+
883
+ @media screen and (max-height: 500px) and (orientation: landscape) {
884
+ .hero-section {
885
+ padding: 0.5rem;
886
+ }
887
+ .title {
888
+ font-size: 2.5rem;
889
+ margin-bottom: 0.3rem;
890
+ }
891
+ .subtitle {
892
+ font-size: 1rem;
893
+ margin-bottom: 0.3rem;
894
+ }
895
+ .description {
896
+ font-size: 0.8rem;
897
+ margin-bottom: 0.8rem;
898
+ }
899
+ .cta-button {
900
+ padding: 6px 15px;
901
+ font-size: 0.8rem;
902
+ }
903
+ .theme-selector {
904
+ margin: 0.5rem 0;
905
+ }
906
+ .theme-label {
907
+ margin-bottom: 0.3rem;
908
+ }
909
+ .theme-options .theme-option {
910
+ width: 45px !important;
911
+ height: 45px !important;
912
+ margin: 0 2px 5px;
913
+ }
914
+
915
+ .theme-options .theme-option .theme-icon-container {
916
+ width: 18px !important;
917
+ height: 18px !important;
918
+ }
919
+
920
+ .theme-options .theme-option .theme-name {
921
+ font-size: 0.55rem !important;
922
+ }
923
+ }
924
+
925
+ /* 字体清晰度优化 */
926
+ @supports (font-variation-settings: normal) {
927
+ * {
928
+ font-variation-settings: "wght" var(--font-weight, 400);
929
+ font-synthesis: none;
930
+ }
931
+ }
932
+
933
+ /* 防止字体在不同设备上渲染不一致 */
934
+ @media screen and (-webkit-min-device-pixel-ratio: 2),
935
+ screen and (min-resolution: 192dpi) {
936
+ .title, .subtitle, .description, .description span, .powered-text {
937
+ -webkit-font-smoothing: antialiased;
938
+ -moz-osx-font-smoothing: grayscale;
939
+ }
940
+ }
941
+
942
+ /* 调整 canvas 的层级和混合模式 */
943
+ .matrix-rain {
944
+ position: fixed;
945
+ top: 0;
946
+ left: 0;
947
+ width: 100%;
948
+ height: 100%;
949
+ z-index: 1;
950
+ opacity: 0.4;
951
+ pointer-events: none;
952
+ mix-blend-mode: screen;
953
+ }
954
+
955
+ /* 隐藏所有滚动条 */
956
+ ::-webkit-scrollbar {
957
+ width: 0;
958
+ height: 0;
959
+ background: transparent;
960
+ }
961
+
962
+ * {
963
+ scrollbar-width: none;
964
+ -ms-overflow-style: none;
965
+ }
966
+
967
+ /* 修复某些设备上的overflow问题 */
968
+ html, body {
969
+ overflow-x: hidden;
970
+ -webkit-overflow-scrolling: touch;
971
+ }
972
+
973
+ /* GitHub 链接按钮 */
974
+ .github-link {
975
+ position: fixed;
976
+ top: 20px;
977
+ right: 20px;
978
+ width: 42px;
979
+ height: 42px;
980
+ border-radius: 50%;
981
+ background: linear-gradient(145deg, #222, #000);
982
+ display: flex;
983
+ align-items: center;
984
+ justify-content: center;
985
+ color: white;
986
+ text-decoration: none;
987
+ font-size: 1.6rem;
988
+ box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.6), -2px -2px 8px rgba(255, 255, 255, 0.1);
989
+ transition: all 0.3s ease;
990
+ z-index: 100;
991
+ overflow: hidden;
992
+ border: 1px solid rgba(255, 255, 255, 0.1);
993
+ }
994
+
995
+ .github-link::before {
996
+ content: '';
997
+ position: absolute;
998
+ top: -50%;
999
+ left: -50%;
1000
+ width: 200%;
1001
+ height: 200%;
1002
+ background: linear-gradient(
1003
+ to right,
1004
+ transparent,
1005
+ rgba(255, 255, 255, 0.1),
1006
+ transparent
1007
+ );
1008
+ transform: rotate(45deg);
1009
+ z-index: 1;
1010
+ }
1011
+
1012
+ .github-link:hover {
1013
+ transform: translateY(-3px);
1014
+ box-shadow: 6px 6px 20px rgba(0, 0, 0, 0.7), -3px -3px 10px rgba(255, 255, 255, 0.15);
1015
+ background: linear-gradient(145deg, #444, #111);
1016
+ }
1017
+
1018
+ .github-link i {
1019
+ position: relative;
1020
+ z-index: 2;
1021
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
1022
+ }
1023
+
1024
+ /* 加载页面样式 */
1025
+ .loading-screen {
1026
+ position: fixed;
1027
+ top: 0;
1028
+ left: 0;
1029
+ width: 100%;
1030
+ height: 100%;
1031
+ background-color: var(--background-color);
1032
+ display: flex;
1033
+ flex-direction: column;
1034
+ align-items: center;
1035
+ justify-content: center;
1036
+ z-index: 1000;
1037
+ overflow: hidden;
1038
+ transition: opacity 0.5s ease-out, visibility 0.5s ease-out;
1039
+ }
1040
+
1041
+ .loading-screen.hidden {
1042
+ opacity: 0;
1043
+ visibility: hidden;
1044
+ }
1045
+
1046
+ .loading-container {
1047
+ position: relative;
1048
+ width: 300px;
1049
+ max-width: 80%;
1050
+ }
1051
+
1052
+ .loading-title {
1053
+ font-size: 3rem;
1054
+ font-weight: 800;
1055
+ text-align: center;
1056
+ margin-bottom: 2rem;
1057
+ background: linear-gradient(45deg, var(--primary-color), var(--accent-color-5));
1058
+ background-size: 200% auto;
1059
+ -webkit-background-clip: text;
1060
+ background-clip: text;
1061
+ -webkit-text-fill-color: transparent;
1062
+ letter-spacing: 5px;
1063
+ position: relative;
1064
+ filter: drop-shadow(0 0 8px rgba(0, 255, 204, 0.3));
1065
+ font-family: var(--font-mono);
1066
+ animation: glitch-text 1s infinite, loading-title-animation 1.5s forwards;
1067
+ }
1068
+
1069
+ .loading-background {
1070
+ position: absolute;
1071
+ top: 0;
1072
+ left: 0;
1073
+ width: 100%;
1074
+ height: 100%;
1075
+ background: radial-gradient(circle at center, rgba(0, 255, 204, 0.05), transparent 70%);
1076
+ z-index: -1;
1077
+ }
1078
+
1079
+ .loading-grid {
1080
+ position: absolute;
1081
+ top: 0;
1082
+ left: 0;
1083
+ right: 0;
1084
+ bottom: 0;
1085
+ background-image:
1086
+ linear-gradient(rgba(0, 255, 204, 0.1) 1px, transparent 1px),
1087
+ linear-gradient(90deg, rgba(0, 255, 204, 0.1) 1px, transparent 1px);
1088
+ background-size: 40px 40px;
1089
+ opacity: 0.15;
1090
+ z-index: -1;
1091
+ animation: grid-animation 20s linear infinite;
1092
+ }
1093
+
1094
+ .progress-container {
1095
+ width: 100%;
1096
+ height: 6px;
1097
+ background: rgba(10, 30, 30, 0.5);
1098
+ border-radius: 3px;
1099
+ overflow: hidden;
1100
+ position: relative;
1101
+ box-shadow: 0 0 10px rgba(0, 255, 204, 0.3);
1102
+ }
1103
+
1104
+ .progress-bar {
1105
+ height: 100%;
1106
+ width: 0%;
1107
+ background: linear-gradient(90deg, var(--accent-color-5), var(--primary-color));
1108
+ position: relative;
1109
+ border-radius: 3px;
1110
+ transition: width 0.05s ease-out;
1111
+ }
1112
+
1113
+ .progress-bar::before {
1114
+ content: '';
1115
+ position: absolute;
1116
+ top: 0;
1117
+ left: 0;
1118
+ width: 100%;
1119
+ height: 100%;
1120
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
1121
+ animation: progress-shine 1s linear infinite;
1122
+ }
1123
+
1124
+ .progress-bar::after {
1125
+ content: '';
1126
+ position: absolute;
1127
+ top: 0;
1128
+ right: 0;
1129
+ width: 5px;
1130
+ height: 100%;
1131
+ background: rgba(255, 255, 255, 0.8);
1132
+ box-shadow: 0 0 10px rgba(0, 255, 204, 0.8);
1133
+ animation: pulse 0.5s ease-in-out infinite alternate;
1134
+ }
1135
+
1136
+ .progress-text {
1137
+ font-family: var(--font-mono);
1138
+ text-align: right;
1139
+ margin-top: 0.5rem;
1140
+ font-size: 1rem;
1141
+ color: var(--primary-color);
1142
+ text-shadow: 0 0 5px rgba(0, 255, 204, 0.5);
1143
+ font-weight: 500;
1144
+ letter-spacing: 1px;
1145
+ }
1146
+
1147
+ .glitch-effect {
1148
+ position: absolute;
1149
+ top: 0;
1150
+ left: 0;
1151
+ width: 100%;
1152
+ height: 100%;
1153
+ background: transparent;
1154
+ mix-blend-mode: overlay;
1155
+ pointer-events: none;
1156
+ z-index: 10;
1157
+ }
1158
+
1159
+ .glitch-line {
1160
+ position: absolute;
1161
+ width: 100%;
1162
+ height: 1px;
1163
+ background-color: rgba(0, 255, 204, 0.5);
1164
+ opacity: 0;
1165
+ }
1166
+
1167
+ .glitch-line:nth-child(1) { top: 20%; animation: glitch-line-animation 3s infinite 0.5s; }
1168
+ .glitch-line:nth-child(2) { top: 40%; animation: glitch-line-animation 4s infinite 1s; }
1169
+ .glitch-line:nth-child(3) { top: 60%; animation: glitch-line-animation 2.5s infinite 1.5s; }
1170
+ .glitch-line:nth-child(4) { top: 80%; animation: glitch-line-animation 3.5s infinite 0.2s; }
1171
+
1172
+ .loading-message {
1173
+ font-family: var(--font-mono);
1174
+ margin-top: 1.5rem;
1175
+ font-size: 0.9rem;
1176
+ color: var(--accent-color-5);
1177
+ letter-spacing: 1px;
1178
+ text-align: center;
1179
+ opacity: 0.8;
1180
+ max-width: 80%;
1181
+ animation: typing 3s steps(30, end) infinite;
1182
+ white-space: nowrap;
1183
+ overflow: hidden;
1184
+ position: relative;
1185
+ }
1186
+
1187
+ /* 自定义光标样式 */
1188
+ .loading-message::after {
1189
+ content: '';
1190
+ display: inline-block;
1191
+ width: 8px;
1192
+ height: 16px;
1193
+ background-color: var(--accent-color-5);
1194
+ margin-left: 2px;
1195
+ animation: cursor-blink 0.8s step-end infinite;
1196
+ border-radius: 1px;
1197
+ box-shadow: 0 0 8px var(--accent-color-5);
1198
+ vertical-align: middle;
1199
+ position: relative;
1200
+ top: -1px;
1201
+ }
1202
+
1203
+ @keyframes cursor-blink {
1204
+ 0%, 50% { opacity: 1; }
1205
+ 51%, 100% { opacity: 0; }
1206
+ }
1207
+
1208
+ /* 过渡故障特效 */
1209
+ .transition-glitch {
1210
+ position: fixed;
1211
+ top: 0;
1212
+ left: 0;
1213
+ width: 100%;
1214
+ height: 100%;
1215
+ background-color: rgba(0, 0, 0, 0.8);
1216
+ z-index: 999;
1217
+ opacity: 0;
1218
+ pointer-events: none;
1219
+ transition: opacity 0.2s ease;
1220
+ }
1221
+
1222
+ .transition-glitch.active {
1223
+ opacity: 1;
1224
+ animation: transition-flicker 0.5s ease-out forwards;
1225
+ }
1226
+
1227
+ .glitch-stripe {
1228
+ position: absolute;
1229
+ width: 100%;
1230
+ height: 10vh;
1231
+ background-color: rgba(0, 255, 204, 0.15);
1232
+ transform: translateX(-100%);
1233
+ }
1234
+
1235
+ .glitch-stripe:nth-child(1) {
1236
+ top: 15%;
1237
+ animation: glitch-stripe-move 0.3s cubic-bezier(0.2, 0.6, 0.8, 0.4) 0.1s forwards;
1238
+ height: 8vh;
1239
+ }
1240
+ .glitch-stripe:nth-child(2) {
1241
+ top: 45%;
1242
+ animation: glitch-stripe-move 0.25s cubic-bezier(0.3, 0.8, 0.7, 0.2) 0.2s forwards;
1243
+ height: 12vh;
1244
+ background-color: rgba(170, 0, 255, 0.12);
1245
+ }
1246
+ .glitch-stripe:nth-child(3) {
1247
+ top: 70%;
1248
+ animation: glitch-stripe-move 0.35s cubic-bezier(0.1, 0.7, 0.9, 0.3) 0.15s forwards;
1249
+ height: 6vh;
1250
+ background-color: rgba(255, 0, 170, 0.1);
1251
+ }
1252
+
1253
+ @keyframes glitch-stripe-move {
1254
+ 0% { transform: translateX(-100%) skewY(2deg); filter: hue-rotate(0deg); }
1255
+ 60% { filter: hue-rotate(45deg); }
1256
+ 100% { transform: translateX(100%) skewY(-2deg); filter: hue-rotate(0deg); }
1257
+ }
1258
+
1259
+ @keyframes transition-flicker {
1260
+ 0% { opacity: 0; filter: brightness(1); }
1261
+ 5% { opacity: 0.8; filter: brightness(1.5) contrast(1.2); }
1262
+ 10% { opacity: 0.2; filter: brightness(0.8) contrast(1.5); }
1263
+ 15% { opacity: 0.9; filter: brightness(1.2) contrast(0.8) hue-rotate(10deg); }
1264
+ 20% { opacity: 0.3; filter: brightness(1.5) contrast(1.3); }
1265
+ 30% { opacity: 0.8; filter: brightness(0.9) contrast(1.8) hue-rotate(-15deg); }
1266
+ 40% { opacity: 0.2; filter: brightness(1.2) contrast(0.7); }
1267
+ 50% { opacity: 0.9; filter: brightness(1.1) contrast(1.2); }
1268
+ 60% { opacity: 0.3; filter: brightness(1.3) contrast(1.1) hue-rotate(5deg); }
1269
+ 80% { opacity: 0.2; filter: brightness(1) contrast(1); }
1270
+ 100% { opacity: 0; filter: brightness(1) contrast(1); }
1271
+ }
1272
+
1273
+ /* 故障线条 */
1274
+ .glitch-line-horizontal {
1275
+ position: absolute;
1276
+ width: 100%;
1277
+ height: 2px;
1278
+ background-color: var(--accent-color-5);
1279
+ opacity: 0;
1280
+ left: 0;
1281
+ z-index: 1000;
1282
+ }
1283
+
1284
+ .glitch-line-horizontal:nth-child(4) { top: 30%; animation: glitch-h-line 0.2s linear 0.1s; }
1285
+ .glitch-line-horizontal:nth-child(5) { top: 60%; animation: glitch-h-line 0.2s linear 0.25s; }
1286
+ .glitch-line-horizontal:nth-child(6) { top: 80%; animation: glitch-h-line 0.2s linear 0.15s; }
1287
+
1288
+ @keyframes glitch-h-line {
1289
+ 0% { transform: translateX(-100%); opacity: 0.7; }
1290
+ 100% { transform: translateX(100%); opacity: 0; }
1291
+ }
1292
+
1293
+ /* 进度条动画效果 */
1294
+ @keyframes progress-shine {
1295
+ 0% { transform: translateX(-100%); }
1296
+ 100% { transform: translateX(100%); }
1297
+ }
1298
+
1299
+ @keyframes pulse {
1300
+ 0% { opacity: 0.5; }
1301
+ 100% { opacity: 1; }
1302
+ }
1303
+
1304
+ @keyframes grid-animation {
1305
+ 0% { transform: translateY(0); }
1306
+ 100% { transform: translateY(40px); }
1307
+ }
1308
+
1309
+ @keyframes typing {
1310
+ 0% { width: 0; }
1311
+ 50% { width: 100%; }
1312
+ 90% { width: 100%; }
1313
+ 100% { width: 0; }
1314
+ }
1315
+
1316
+ @keyframes glitch-line-animation {
1317
+ 0% { opacity: 0; transform: translateX(-100%); }
1318
+ 10% { opacity: 0.8; transform: translateX(0); }
1319
+ 15% { opacity: 0; transform: translateX(100%); }
1320
+ 20% { opacity: 0; }
1321
+ 100% { opacity: 0; }
1322
+ }
1323
+
1324
+ @keyframes glitch-text {
1325
+ 0% { transform: translate(0); }
1326
+ 20% { transform: translate(-2px, 2px); }
1327
+ 40% { transform: translate(-2px, -2px); }
1328
+ 60% { transform: translate(2px, 2px); }
1329
+ 80% { transform: translate(2px, -2px); }
1330
+ 100% { transform: translate(0); }
1331
+ }
1332
+
1333
+ @keyframes loading-title-animation {
1334
+ 0% { clip-path: inset(0 100% 0 0); }
1335
+ 100% { clip-path: inset(0 0 0 0); }
1336
+ }
1337
+
1338
+ /* 数字字符故障效果 */
1339
+ .digital-glitch {
1340
+ position: relative;
1341
+ display: inline-block;
1342
+ color: var(--primary-color);
1343
+ font-family: var(--font-mono);
1344
+ font-weight: bold;
1345
+ mix-blend-mode: exclusion;
1346
+ animation: digital-glitch 3s infinite;
1347
+ }
1348
+
1349
+ @keyframes digital-glitch {
1350
+ 0% { opacity: 1; }
1351
+ 7% { opacity: 1; text-shadow: 0 0 5px var(--primary-color); }
1352
+ 8% { opacity: 0; text-shadow: none; }
1353
+ 9% { opacity: 1; }
1354
+ 10% { opacity: 1; text-shadow: 0 0 5px var(--primary-color); }
1355
+ 11% { opacity: 0; text-shadow: none; }
1356
+ 12% { opacity: 1; }
1357
+ 20% { opacity: 1; }
1358
+ 100% { opacity: 1; }
1359
+ }
1360
+
1361
+ @media screen and (max-width: 768px) {
1362
+ .loading-title {
1363
+ font-size: 2rem;
1364
+ margin-bottom: 1.5rem;
1365
+ }
1366
+
1367
+ .loading-container {
1368
+ width: 250px;
1369
+ }
1370
+
1371
+ .progress-text {
1372
+ font-size: 0.9rem;
1373
+ }
1374
+
1375
+ .loading-message {
1376
+ font-size: 0.8rem;
1377
+ margin-top: 1rem;
1378
+ }
1379
+ }
static/themes/.DS_Store ADDED
Binary file (6.15 kB). View file
 
static/themes/README.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenManus 主题系统
2
+
3
+ 本文件夹包含OpenManus的不同用户界面主题。
4
+
5
+ ## 主题结构
6
+
7
+ 每个主题必须遵循以下文件结构:
8
+
9
+ ```
10
+ 主题名称/
11
+ ├── static/
12
+ │ ├── style.css (必需)
13
+ │ ├── main.js (必需)
14
+ │ └── ... (其他静态资源)
15
+ ├── templates/
16
+ │ └── chat.html (必需)
17
+ └── theme.json (必需)
18
+ ```
19
+
20
+ ## 如何添加新主题
21
+
22
+ 1. 在`themes`文件夹中创建一个新文件夹,使用你的主题名称
23
+ 2. 复制`static`和`templates`文件夹结构
24
+ 3. 创建`theme.json`文件,包含以下内容:
25
+
26
+ ```json
27
+ {
28
+ "name": "主题的中文名称",
29
+ "description": "主题的简短描述",
30
+ "author": "作者名",
31
+ "version": "1.0.0"
32
+ }
33
+ ```
34
+
35
+ 4. 修改CSS和HTML文件以实现你想要的外观
36
+
37
+ ## 路径引用
38
+
39
+ 在`chat.html`中,确保使用以下路径格式引用资源:
40
+
41
+ ```html
42
+ <link rel="stylesheet" href="/static/themes/你的主题名称/static/style.css">
43
+ <script src="/static/themes/你的主题名称/static/main.js"></script>
44
+ ```
45
+
46
+ ## 示例主题
47
+
48
+ - `Normal`: 默认主题
49
+ - `cyberpunk`: 赛博朋克主题
50
+
51
+ 当你添加新主题后,系统会自动在首页显示它作为可选项。
static/themes/cyberpunk/static/logo_white.png ADDED

Git LFS Details

  • SHA256: 12f4e878e80ae3d429573b9fd31001870ed62f41656b72b6d7f864f17fbe0fce
  • Pointer size: 131 Bytes
  • Size of remote file: 122 kB
static/themes/cyberpunk/static/main.js ADDED
@@ -0,0 +1,1255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let currentEventSource = null;
2
+ let historyVisible = false; // Track history panel status
3
+
4
+ function createTask() {
5
+ const promptInput = document.getElementById('prompt-input');
6
+ const prompt = promptInput.value.trim();
7
+
8
+ if (!prompt) {
9
+ alert("Please enter a valid task");
10
+ promptInput.focus();
11
+ return;
12
+ }
13
+
14
+ if (currentEventSource) {
15
+ currentEventSource.close();
16
+ currentEventSource = null;
17
+ }
18
+
19
+ const taskContainer = document.getElementById('task-container');
20
+ const stepsContainer = document.getElementById('steps-container');
21
+ const resultContainer = document.getElementById('result-container');
22
+ const container = document.querySelector('.container');
23
+ const resultPanel = document.getElementById('result-panel');
24
+
25
+ // 重置UI状态
26
+ resetUIState();
27
+
28
+ // Hide welcome message, show step loading status
29
+ const welcomeMessage = taskContainer.querySelector('.welcome-message');
30
+ if (welcomeMessage) {
31
+ welcomeMessage.style.display = 'none';
32
+ }
33
+
34
+ stepsContainer.innerHTML = '<div class="loading">Initializing task...</div>';
35
+ resultContainer.innerHTML = '';
36
+
37
+ // Close history panel on mobile devices
38
+ closeHistoryOnMobile();
39
+
40
+ fetch('/tasks', {
41
+ method: 'POST',
42
+ headers: {
43
+ 'Content-Type': 'application/json'
44
+ },
45
+ body: JSON.stringify({ prompt })
46
+ })
47
+ .then(response => {
48
+ if (!response.ok) {
49
+ return response.json().then(err => { throw new Error(err.detail || 'Request failed') });
50
+ }
51
+ return response.json();
52
+ })
53
+ .then(data => {
54
+ if (!data.task_id) {
55
+ throw new Error('Invalid task ID');
56
+ }
57
+ setupSSE(data.task_id);
58
+ loadHistory();
59
+ promptInput.value = '';
60
+ })
61
+ .catch(error => {
62
+ stepsContainer.innerHTML = `<div class="error">Error: ${error.message}</div>`;
63
+ updateResultPanel({result: error.message}, 'error');
64
+ showResultPanel();
65
+ console.error('Failed to create task:', error);
66
+ });
67
+ }
68
+
69
+ // 重置UI状态的独立函数,避免重复代码
70
+ function resetUIState() {
71
+ const container = document.querySelector('.container');
72
+ const resultPanel = document.getElementById('result-panel');
73
+
74
+ // 重置容器布局
75
+ container.classList.remove('with-result');
76
+ container.style.width = '98%';
77
+
78
+ // 确保结果面板完全隐藏
79
+ if (resultPanel) {
80
+ resultPanel.classList.add('hidden');
81
+ resultPanel.style.display = 'none';
82
+ }
83
+
84
+ // 触发布局调整
85
+ handleResponsiveLayout();
86
+ }
87
+
88
+ function setupSSE(taskId) {
89
+ let retryCount = 0;
90
+ const maxRetries = 3;
91
+ const retryDelay = 2000;
92
+ let lastResultContent = '';
93
+ let stepsData = [];
94
+
95
+ const stepsContainer = document.getElementById('steps-container');
96
+ const resultContainer = document.getElementById('result-container');
97
+
98
+ // Hide result panel by default
99
+ hideResultPanel();
100
+
101
+ function connect() {
102
+ const eventSource = new EventSource(`/tasks/${taskId}/events`);
103
+ currentEventSource = eventSource;
104
+
105
+ let heartbeatTimer = setInterval(() => {
106
+ const pingDiv = document.createElement('div');
107
+ pingDiv.className = 'ping';
108
+ pingDiv.innerHTML = '·';
109
+ stepsContainer.appendChild(pingDiv);
110
+ }, 5000);
111
+
112
+ // Initial polling
113
+ fetch(`/tasks/${taskId}`)
114
+ .then(response => response.json())
115
+ .then(task => {
116
+ updateTaskStatus(task);
117
+ })
118
+ .catch(error => {
119
+ console.error('Initial status retrieval failed:', error);
120
+ });
121
+
122
+ const handleEvent = (event, type) => {
123
+ clearInterval(heartbeatTimer);
124
+ try {
125
+ const data = JSON.parse(event.data);
126
+ const loadingDiv = stepsContainer.querySelector('.loading');
127
+ if (loadingDiv) loadingDiv.remove();
128
+
129
+ const { formattedContent, timestamp, isoTimestamp } = formatStepContent(data, type);
130
+
131
+ stepsData.push({
132
+ type: type,
133
+ content: formattedContent,
134
+ timestamp: timestamp,
135
+ isoTimestamp: isoTimestamp,
136
+ element: createStepElement(type, formattedContent, timestamp)
137
+ });
138
+
139
+ stepsData.sort((a, b) => {
140
+ return new Date(a.isoTimestamp) - new Date(b.isoTimestamp);
141
+ });
142
+
143
+ stepsContainer.innerHTML = '';
144
+ stepsData.forEach(step => {
145
+ stepsContainer.appendChild(step.element);
146
+ });
147
+
148
+ document.querySelectorAll('.step-item').forEach(item => {
149
+ item.classList.remove('active');
150
+ });
151
+
152
+ const latestStep = stepsData[stepsData.length - 1];
153
+ if (latestStep && latestStep.element) {
154
+ latestStep.element.classList.add('active');
155
+ }
156
+
157
+ autoScroll(stepsContainer);
158
+
159
+ if (type === 'tool' || type === 'act' || type === 'result') {
160
+ updateResultPanel(data, type);
161
+ showResultPanel();
162
+ }
163
+
164
+ fetch(`/tasks/${taskId}`)
165
+ .then(response => response.json())
166
+ .then(task => {
167
+ updateTaskStatus(task);
168
+ })
169
+ .catch(error => {
170
+ console.error('Failed to update status:', error);
171
+ });
172
+ } catch (e) {
173
+ console.error(`Error processing ${type} event:`, e);
174
+ }
175
+ };
176
+
177
+ const eventTypes = ['think', 'tool', 'act', 'log', 'run', 'message'];
178
+ eventTypes.forEach(type => {
179
+ eventSource.addEventListener(type, (event) => handleEvent(event, type));
180
+ });
181
+
182
+ eventSource.addEventListener('complete', (event) => {
183
+ clearInterval(heartbeatTimer);
184
+ try {
185
+ const data = JSON.parse(event.data);
186
+ lastResultContent = data.result || '';
187
+
188
+ const completeDiv = document.createElement('div');
189
+ completeDiv.className = 'complete';
190
+ completeDiv.innerHTML = '<div>✅ Task completed</div>';
191
+ stepsContainer.appendChild(completeDiv);
192
+
193
+ updateResultPanel({result: lastResultContent}, 'complete');
194
+ showResultPanel();
195
+
196
+ fetch(`/tasks/${taskId}`)
197
+ .then(response => response.json())
198
+ .then(task => {
199
+ updateTaskStatus(task);
200
+ })
201
+ .catch(error => {
202
+ console.error('Failed to update final status:', error);
203
+ });
204
+
205
+ eventSource.close();
206
+ currentEventSource = null;
207
+ } catch (e) {
208
+ console.error('Error processing completion event:', e);
209
+ }
210
+ });
211
+
212
+ eventSource.addEventListener('error', (event) => {
213
+ clearInterval(heartbeatTimer);
214
+ try {
215
+ const data = JSON.parse(event.data);
216
+ const errorDiv = document.createElement('div');
217
+ errorDiv.className = 'error';
218
+ errorDiv.innerHTML = `<div>❌ Error: ${data.message}</div>`;
219
+ stepsContainer.appendChild(errorDiv);
220
+
221
+ updateResultPanel({result: data.message}, 'error');
222
+ showResultPanel();
223
+
224
+ eventSource.close();
225
+ currentEventSource = null;
226
+ } catch (e) {
227
+ console.error('Error processing error:', e);
228
+ }
229
+ });
230
+
231
+ eventSource.onerror = (err) => {
232
+ if (eventSource.readyState === EventSource.CLOSED) return;
233
+
234
+ console.error('SSE connection error:', err);
235
+ clearInterval(heartbeatTimer);
236
+ eventSource.close();
237
+
238
+ fetch(`/tasks/${taskId}`)
239
+ .then(response => response.json())
240
+ .then(task => {
241
+ if (task.status === 'completed' || task.status === 'failed') {
242
+ updateTaskStatus(task);
243
+ if (task.status === 'completed') {
244
+ const completeDiv = document.createElement('div');
245
+ completeDiv.className = 'complete';
246
+ completeDiv.innerHTML = '<div>✅ Task completed</div>';
247
+ stepsContainer.appendChild(completeDiv);
248
+
249
+ if (task.steps && task.steps.length > 0) {
250
+ const lastStep = task.steps[task.steps.length - 1];
251
+ updateResultPanel({result: lastStep.result}, 'complete');
252
+ showResultPanel();
253
+ }
254
+ } else {
255
+ const errorDiv = document.createElement('div');
256
+ errorDiv.className = 'error';
257
+ errorDiv.innerHTML = `<div>❌ Error: ${task.error || 'Task failed'}</div>`;
258
+ stepsContainer.appendChild(errorDiv);
259
+
260
+ updateResultPanel({result: task.error || 'Task failed'}, 'error');
261
+ showResultPanel();
262
+ }
263
+ } else if (retryCount < maxRetries) {
264
+ retryCount++;
265
+ const warningDiv = document.createElement('div');
266
+ warningDiv.className = 'warning';
267
+ warningDiv.innerHTML = `<div>⚠ Connection lost, retrying in ${retryDelay/1000} seconds (${retryCount}/${maxRetries})...</div>`;
268
+ stepsContainer.appendChild(warningDiv);
269
+ setTimeout(connect, retryDelay);
270
+ } else {
271
+ const errorDiv = document.createElement('div');
272
+ errorDiv.className = 'error';
273
+ errorDiv.innerHTML = '<div>⚠ Connection lost, please refresh the page</div>';
274
+ stepsContainer.appendChild(errorDiv);
275
+
276
+ updateResultPanel({result: 'Connection lost, please refresh the page'}, 'error');
277
+ showResultPanel();
278
+ }
279
+ })
280
+ .catch(error => {
281
+ console.error('Failed to check task status:', error);
282
+ if (retryCount < maxRetries) {
283
+ retryCount++;
284
+ setTimeout(connect, retryDelay);
285
+ }
286
+ });
287
+ };
288
+ }
289
+
290
+ connect();
291
+ }
292
+
293
+ function updateResultPanel(data, type) {
294
+ const resultContainer = document.getElementById('result-container');
295
+ const currentStep = document.getElementById('current-step');
296
+
297
+ if (!resultContainer || !currentStep) return;
298
+
299
+ // Update top step information
300
+ const typeLabel = getEventLabel(type);
301
+ const icon = getEventIcon(type);
302
+
303
+ // Clear and build new UI
304
+ currentStep.innerHTML = '';
305
+ currentStep.setAttribute('data-type', type); // 添加类型属性
306
+
307
+ // Add icon
308
+ const iconSpan = document.createElement('span');
309
+ iconSpan.className = 'emoji-icon';
310
+ iconSpan.innerHTML = icon; // 使用innerHTML而不是textContent以支持HTML标签
311
+ currentStep.appendChild(iconSpan);
312
+
313
+ // Create status text element, add typewriter effect
314
+ const statusText = document.createElement('span');
315
+ statusText.className = 'status-text';
316
+ currentStep.appendChild(statusText);
317
+
318
+ // Typewriter effect displaying status text
319
+ let i = 0;
320
+ let typingEffect = setInterval(() => {
321
+ if (i < typeLabel.length) {
322
+ statusText.textContent += typeLabel.charAt(i);
323
+ i++;
324
+ } else {
325
+ clearInterval(typingEffect);
326
+ }
327
+ }, 50);
328
+
329
+ // Update content area
330
+ let content = '';
331
+
332
+ if (data.result) {
333
+ content = data.result;
334
+ } else if (data.message) {
335
+ content = data.message;
336
+ } else {
337
+ content = JSON.stringify(data, null, 2);
338
+ }
339
+
340
+ // Clear previous content, add new content
341
+ resultContainer.innerHTML = '';
342
+
343
+ // Create content area with proper styling for overflow control
344
+ const contentDiv = document.createElement('div');
345
+ contentDiv.classList.add('content-box');
346
+ contentDiv.style.width = '100%';
347
+ contentDiv.style.maxWidth = '100%';
348
+ contentDiv.style.boxSizing = 'border-box';
349
+ contentDiv.style.overflowWrap = 'break-word';
350
+ contentDiv.style.wordWrap = 'break-word';
351
+ contentDiv.style.wordBreak = 'break-word';
352
+
353
+ const preElement = document.createElement('pre');
354
+ preElement.style.whiteSpace = 'pre-wrap';
355
+ preElement.style.wordWrap = 'break-word';
356
+ preElement.style.wordBreak = 'break-word';
357
+ preElement.style.maxWidth = '100%';
358
+ preElement.style.boxSizing = 'border-box';
359
+ preElement.textContent = content;
360
+
361
+ contentDiv.appendChild(preElement);
362
+ resultContainer.appendChild(contentDiv);
363
+
364
+ // Ensure proper scrolling
365
+ setTimeout(() => {
366
+ resultContainer.scrollTop = 0;
367
+ }, 100);
368
+ }
369
+
370
+ function loadHistory() {
371
+ fetch('/tasks')
372
+ .then(response => {
373
+ if (!response.ok) {
374
+ return response.text().then(text => {
375
+ throw new Error(`Request failed: ${response.status} - ${text.substring(0, 100)}`);
376
+ });
377
+ }
378
+ return response.json();
379
+ })
380
+ .then(tasks => {
381
+ const listContainer = document.getElementById('task-list');
382
+ if (tasks.length === 0) {
383
+ listContainer.innerHTML = '<div class="info">No history tasks</div>';
384
+ return;
385
+ }
386
+
387
+ // Update history count
388
+ const historyCount = document.querySelector('.history-count');
389
+ if (historyCount) {
390
+ historyCount.textContent = tasks.length;
391
+ }
392
+
393
+ listContainer.innerHTML = tasks.map(task => `
394
+ <div class="task-card" data-task-id="${task.id}" onclick="loadTask('${task.id}')">
395
+ <div class="task-title">${task.prompt}</div>
396
+ <div class="task-meta">
397
+ <span>${new Date(task.created_at).toLocaleString()}</span>
398
+ <span class="status status-${task.status ? task.status.toLowerCase() : 'unknown'}">
399
+ ${getStatusText(task.status)}
400
+ </span>
401
+ </div>
402
+ </div>
403
+ `).join('');
404
+ })
405
+ .catch(error => {
406
+ console.error('Failed to load history:', error);
407
+ const listContainer = document.getElementById('task-list');
408
+ listContainer.innerHTML = `<div class="error">Loading failed: ${error.message}</div>`;
409
+ });
410
+ }
411
+
412
+ function loadTask(taskId) {
413
+ if (currentEventSource) {
414
+ currentEventSource.close();
415
+ currentEventSource = null;
416
+ }
417
+
418
+ const taskContainer = document.getElementById('task-container');
419
+ const stepsContainer = document.getElementById('steps-container');
420
+ const resultContainer = document.getElementById('result-container');
421
+
422
+ // 重置UI状态
423
+ resetUIState();
424
+
425
+ // Hide welcome message
426
+ const welcomeMessage = taskContainer.querySelector('.welcome-message');
427
+ if (welcomeMessage) {
428
+ welcomeMessage.style.display = 'none';
429
+ }
430
+
431
+ stepsContainer.innerHTML = '<div class="loading">Loading task...</div>';
432
+ resultContainer.innerHTML = '';
433
+
434
+ // Close history panel on mobile devices
435
+ closeHistoryOnMobile();
436
+
437
+ fetch(`/tasks/${taskId}`)
438
+ .then(response => response.json())
439
+ .then(task => {
440
+ // 高亮当前选中的任务卡片
441
+ highlightTaskCard(taskId);
442
+
443
+ stepsContainer.innerHTML = '';
444
+ if (task.steps && task.steps.length > 0) {
445
+ // 按时间戳排序渲染步骤
446
+ renderSortedSteps(task.steps, task.created_at);
447
+ } else {
448
+ stepsContainer.innerHTML = '<div class="info">No steps recorded for this task</div>';
449
+ }
450
+
451
+ updateTaskStatus(task);
452
+ })
453
+ .catch(error => {
454
+ console.error('Failed to load task:', error);
455
+ stepsContainer.innerHTML = `<div class="error">Error: ${error.message}</div>`;
456
+ });
457
+ }
458
+
459
+ // 高亮当前选中的任务卡片
460
+ function highlightTaskCard(taskId) {
461
+ const taskCards = document.querySelectorAll('.task-card');
462
+ taskCards.forEach(card => {
463
+ card.classList.remove('active');
464
+ if (card.getAttribute('data-task-id') === taskId) {
465
+ card.classList.add('active');
466
+ }
467
+ });
468
+ }
469
+
470
+ // 按时间戳排序渲染步骤
471
+ function renderSortedSteps(steps, taskCreatedAt) {
472
+ const stepsContainer = document.getElementById('steps-container');
473
+
474
+ // 存储步骤集合
475
+ let taskSteps = [];
476
+
477
+ steps.forEach((step, index) => {
478
+ const stepTimestamp = new Date(step.created_at || taskCreatedAt).toLocaleTimeString();
479
+ const stepElement = createStepElement(
480
+ step.type,
481
+ step.result,
482
+ stepTimestamp
483
+ );
484
+
485
+ // 将步骤添加到集合
486
+ taskSteps.push({
487
+ index: index,
488
+ timestamp: stepTimestamp,
489
+ isoTimestamp: step.created_at || taskCreatedAt, // 保存ISO时间戳
490
+ element: stepElement,
491
+ step: step
492
+ });
493
+ });
494
+
495
+ // 根据时间戳排序步骤
496
+ taskSteps.sort((a, b) => {
497
+ // 尝试使用ISO时间戳进行比较
498
+ if (a.isoTimestamp && b.isoTimestamp) {
499
+ return new Date(a.isoTimestamp) - new Date(b.isoTimestamp);
500
+ }
501
+
502
+ // 首先按时间戳排序,如果时间相同,按索引排序
503
+ const timeCompare = new Date(a.timestamp) - new Date(b.timestamp);
504
+ return timeCompare !== 0 ? timeCompare : a.index - b.index;
505
+ });
506
+
507
+ // 将排序后的步骤添加到容器
508
+ taskSteps.forEach((stepData, index) => {
509
+ // 只将最后一个步骤设为展开状态
510
+ if (index === taskSteps.length - 1) {
511
+ stepData.element.classList.add('expanded');
512
+ stepData.element.classList.add('active');
513
+
514
+ // 显示最后一个步骤的结果
515
+ updateResultPanel({result: stepData.step.result}, stepData.step.type);
516
+ showResultPanel();
517
+ }
518
+
519
+ stepsContainer.appendChild(stepData.element);
520
+ });
521
+ }
522
+
523
+ function formatStepContent(data, eventType) {
524
+ // 创建具有ISO格式的时间戳,确保排序一致性
525
+ const now = new Date();
526
+ const isoTimestamp = now.toISOString();
527
+ const localTime = now.toLocaleTimeString();
528
+
529
+ return {
530
+ formattedContent: data.result || (data.message || JSON.stringify(data)),
531
+ timestamp: localTime,
532
+ isoTimestamp: isoTimestamp // 添加ISO格式时间戳,用于排序
533
+ };
534
+ }
535
+
536
+ function createStepElement(type, content, timestamp) {
537
+ const step = document.createElement('div');
538
+
539
+ // Executing step
540
+ const stepRegex = /Executing step (\d+)\/(\d+)/;
541
+ if (type === 'log' && stepRegex.test(content)) {
542
+ const match = content.match(stepRegex);
543
+ const currentStep = parseInt(match[1]);
544
+ const totalSteps = parseInt(match[2]);
545
+
546
+ step.className = 'step-divider';
547
+ step.innerHTML = `
548
+ <div class="step-circle">${currentStep}</div>
549
+ <div class="step-line"></div>
550
+ <div class="step-info">${currentStep}/${totalSteps}</div>
551
+ `;
552
+ } else if (type === 'act') {
553
+ // Check if it contains information about file saving
554
+ const saveRegex = /Content successfully saved to (.+)/;
555
+ const match = content.match(saveRegex);
556
+
557
+ step.className = `step-item ${type}`;
558
+ step.dataset.type = type;
559
+ step.dataset.timestamp = timestamp; // 存储时间戳为数据属性
560
+
561
+ // 获取图标HTML
562
+ const iconHtml = getEventIcon(type);
563
+
564
+ if (match && match[1]) {
565
+ const filePath = match[1].trim();
566
+ const fileName = filePath.split('/').pop();
567
+ const fileExtension = fileName.split('.').pop().toLowerCase();
568
+
569
+ // Handling different types of files
570
+ let fileInteractionHtml = '';
571
+
572
+ if (['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'].includes(fileExtension)) {
573
+ fileInteractionHtml = `
574
+ <div class="file-interaction image-preview">
575
+ <img src="${filePath}" alt="${fileName}" class="preview-image" onclick="showFullImage('${filePath}')">
576
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载图片</a>
577
+ </div>
578
+ `;
579
+ } else if (['mp3', 'wav', 'ogg'].includes(fileExtension)) {
580
+ fileInteractionHtml = `
581
+ <div class="file-interaction audio-player">
582
+ <audio controls src="${filePath}"></audio>
583
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载音频</a>
584
+ </div>
585
+ `;
586
+ } else if (['html', 'js', 'py'].includes(fileExtension)) {
587
+ fileInteractionHtml = `
588
+ <div class="file-interaction code-file">
589
+ <button onclick="simulateRunPython('${filePath}')" class="run-button">▶️ 模拟运行</button>
590
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载文件</a>
591
+ </div>
592
+ `;
593
+ } else {
594
+ fileInteractionHtml = `
595
+ <div class="file-interaction">
596
+ <a href="/download?file_path=${filePath}" download="${fileName}" class="download-link">⬇️ 下载文件: ${fileName}</a>
597
+ </div>
598
+ `;
599
+ }
600
+
601
+ step.innerHTML = `
602
+ <div class="log-header" onclick="toggleStepContent(this)">
603
+ <div class="log-prefix">
604
+ <span class="log-prefix-icon">${iconHtml}</span>
605
+ <span>${getEventLabel(type)}</span>
606
+ <time>${timestamp}</time>
607
+ </div>
608
+ <div class="content-preview">${content.substring(0, 20) + (content.length > 20 ? "..." : "")}</div>
609
+ <div class="step-controls">
610
+ <span class="minimize-btn" onclick="minimizeStep(event, this)"></span>
611
+ </div>
612
+ </div>
613
+ <div class="log-body">
614
+ <div class="log-content">
615
+ <pre>${content}</pre>
616
+ ${fileInteractionHtml}
617
+ </div>
618
+ </div>
619
+ `;
620
+ } else {
621
+ step.innerHTML = `
622
+ <div class="log-header" onclick="toggleStepContent(this)">
623
+ <div class="log-prefix">
624
+ <span class="log-prefix-icon">${iconHtml}</span>
625
+ <span>${getEventLabel(type)}</span>
626
+ <time>${timestamp}</time>
627
+ </div>
628
+ <div class="content-preview">${content.substring(0, 20) + (content.length > 20 ? "..." : "")}</div>
629
+ <div class="step-controls">
630
+ <span class="minimize-btn" onclick="minimizeStep(event, this)"></span>
631
+ </div>
632
+ </div>
633
+ <div class="log-body">
634
+ <div class="log-content">
635
+ <pre>${content}</pre>
636
+ </div>
637
+ </div>
638
+ `;
639
+ }
640
+ } else {
641
+ // Get content preview
642
+ let contentPreview = "";
643
+ if (type === 'think' && content.length > 0) {
644
+ // Extract the first 30 characters of the thinking content as preview
645
+ contentPreview = content.substring(0, 30) + (content.length > 30 ? "..." : "");
646
+ } else if (type === 'tool' && content.includes('selected')) {
647
+ // Tool selection content remains as is
648
+ contentPreview = content;
649
+ } else if (type === 'log') {
650
+ // Log content remains as is, usually short
651
+ contentPreview = content;
652
+ } else {
653
+ // Other types take the first 20 characters
654
+ contentPreview = content.substring(0, 20) + (content.length > 20 ? "..." : "");
655
+ }
656
+
657
+ step.className = `step-item ${type}`;
658
+ step.dataset.type = type;
659
+ step.dataset.timestamp = timestamp; // 存储时间戳为数据属性
660
+
661
+ // 获取图标HTML
662
+ const iconHtml = getEventIcon(type);
663
+
664
+ // 确保时间戳显示在log-prefix中,并将步骤类型标签包装在span标签中
665
+ step.innerHTML = `
666
+ <div class="log-header" onclick="toggleStepContent(this)">
667
+ <div class="log-prefix">
668
+ <span class="log-prefix-icon">${iconHtml}</span>
669
+ <span>${getEventLabel(type)}</span>
670
+ <time>${timestamp}</time>
671
+ </div>
672
+ <div class="content-preview">${contentPreview}</div>
673
+ <div class="step-controls">
674
+ <span class="minimize-btn" onclick="minimizeStep(event, this)"></span>
675
+ </div>
676
+ </div>
677
+ <div class="log-body">
678
+ <div class="log-content">
679
+ <pre>${content}</pre>
680
+ </div>
681
+ </div>
682
+ `;
683
+ }
684
+
685
+ return step;
686
+ }
687
+
688
+ // Toggle display/hide of step content
689
+ function toggleStepContent(header) {
690
+ const stepItem = header.closest('.step-item');
691
+ if (!stepItem) return;
692
+
693
+ const logBody = stepItem.querySelector('.log-body');
694
+ if (!logBody) return;
695
+
696
+ // 关闭其他展开的步骤
697
+ document.querySelectorAll('.step-item.expanded').forEach(item => {
698
+ if (item !== stepItem) {
699
+ item.classList.remove('expanded');
700
+ }
701
+ });
702
+
703
+ // 切换当前步骤的展开状态
704
+ stepItem.classList.toggle('expanded');
705
+
706
+ // 高亮当前步骤
707
+ highlightStep(stepItem);
708
+
709
+ // 如果步骤展开,更新结果面板并显示
710
+ if (stepItem.classList.contains('expanded')) {
711
+ const type = stepItem.dataset.type;
712
+ const content = stepItem.querySelector('pre')?.textContent || '';
713
+
714
+ updateResultPanel({result: content}, type);
715
+ showResultPanel();
716
+ }
717
+
718
+ // 触发布局调整
719
+ handleResponsiveLayout();
720
+ }
721
+
722
+ // Minimize step without toggling expansion
723
+ function minimizeStep(event, btn) {
724
+ event.stopPropagation(); // 阻止事件冒泡
725
+
726
+ const stepItem = btn.closest('.step-item');
727
+ if (!stepItem) return;
728
+
729
+ stepItem.classList.remove('expanded');
730
+
731
+ // 触发布局调整
732
+ handleResponsiveLayout();
733
+ }
734
+
735
+ // Toggle result panel display state
736
+ function toggleResultPanel() {
737
+ const resultPanel = document.getElementById('result-panel');
738
+
739
+ if (!resultPanel) return;
740
+
741
+ if (resultPanel.classList.contains('hidden')) {
742
+ showResultPanel();
743
+ } else {
744
+ hideResultPanel();
745
+ }
746
+ }
747
+
748
+ function hideResultPanel() {
749
+ const resultPanel = document.getElementById('result-panel');
750
+ const container = document.querySelector('.container');
751
+
752
+ if (!resultPanel) return;
753
+
754
+ // 先添加hidden类,触发CSS动画
755
+ resultPanel.classList.add('hidden');
756
+ container.classList.remove('with-result');
757
+
758
+ // 延迟处理样式变化,确保过渡效果
759
+ setTimeout(function() {
760
+ resultPanel.style.display = 'none';
761
+ container.style.width = '98%';
762
+ handleResponsiveLayout();
763
+ }, 300);
764
+ }
765
+
766
+ function showResultPanel() {
767
+ const resultPanel = document.getElementById('result-panel');
768
+ const container = document.querySelector('.container');
769
+ const resultContainer = document.getElementById('result-container');
770
+
771
+ if (!resultPanel) return;
772
+
773
+ // 设置为可见
774
+ resultPanel.style.display = 'flex';
775
+ resultPanel.style.flexDirection = 'column';
776
+
777
+ // 确保结果容器可滚动且内容不溢出
778
+ if (resultContainer) {
779
+ resultContainer.style.overflowY = 'auto';
780
+ resultContainer.style.overflowX = 'hidden';
781
+ resultContainer.style.maxHeight = 'calc(100vh - 200px)';
782
+ resultContainer.style.width = '100%';
783
+ resultContainer.style.wordWrap = 'break-word';
784
+ resultContainer.style.wordBreak = 'break-word';
785
+ resultContainer.style.boxSizing = 'border-box';
786
+ resultContainer.style.padding = '5px 10px 15px 5px';
787
+
788
+ // 应用内容溢出处理
789
+ ensureContentFitsContainer(resultContainer);
790
+ }
791
+
792
+ // 使用setTimeout确保DOM更新
793
+ setTimeout(() => {
794
+ resultPanel.classList.remove('hidden');
795
+ container.classList.add('with-result');
796
+
797
+ // 调整容器宽度
798
+ if (window.innerWidth > 1024) {
799
+ container.style.width = 'calc(68% - 10px)';
800
+ // 确保结果面板的视觉效果正确显示
801
+ resultPanel.style.transform = 'translateX(0)';
802
+ }
803
+
804
+ // 触发布局调整
805
+ handleResponsiveLayout();
806
+
807
+ // 再次应用内容溢出处理,确保所有内容都适应容器
808
+ if (resultContainer) {
809
+ ensureContentFitsContainer(resultContainer);
810
+ }
811
+ }, 50);
812
+ }
813
+
814
+ function autoScroll(element) {
815
+ if (element) {
816
+ element.scrollTop = element.scrollHeight;
817
+ }
818
+ }
819
+
820
+ // 综合处理响应式布局的函数
821
+ function handleResponsiveLayout() {
822
+ const container = document.querySelector('.container');
823
+ const resultPanel = document.getElementById('result-panel');
824
+ const stepsContainer = document.getElementById('steps-container');
825
+ const resultContainer = document.getElementById('result-container');
826
+ const isMobile = window.innerWidth <= 768;
827
+ const isTablet = window.innerWidth <= 1024 && window.innerWidth > 768;
828
+
829
+ // 确保滚动容器始终可滚动
830
+ if (stepsContainer) {
831
+ stepsContainer.style.overflowY = 'auto';
832
+ stepsContainer.style.overflowX = 'hidden';
833
+ }
834
+
835
+ if (resultContainer) {
836
+ resultContainer.style.overflowY = 'auto';
837
+ resultContainer.style.overflowX = 'hidden';
838
+ resultContainer.style.maxHeight = isMobile ? 'calc(50vh - 150px)' : 'calc(100vh - 200px)';
839
+ resultContainer.style.width = '100%';
840
+ resultContainer.style.boxSizing = 'border-box';
841
+
842
+ // 确保内容不会溢出
843
+ ensureContentFitsContainer(resultContainer);
844
+ }
845
+
846
+ // 调整步骤项布局
847
+ adjustStepItemsLayout();
848
+
849
+ // 根据屏幕尺寸调整容器宽度
850
+ if (window.innerWidth <= 1024) {
851
+ // 平板和手机布局
852
+ container.style.width = '98%';
853
+ } else {
854
+ // 桌面布局
855
+ if (resultPanel && !resultPanel.classList.contains('hidden')) {
856
+ container.style.width = 'calc(68% - 10px)';
857
+ container.classList.add('with-result');
858
+ } else {
859
+ container.style.width = '98%';
860
+ container.classList.remove('with-result');
861
+ }
862
+ }
863
+
864
+ // 根据屏幕尺寸确定历史面板显示
865
+ if (historyVisible) {
866
+ if (window.innerWidth > 768) {
867
+ container.classList.add('with-history');
868
+ } else {
869
+ container.classList.remove('with-history');
870
+ }
871
+ }
872
+ }
873
+
874
+ // 确保内容适合容器
875
+ function ensureContentFitsContainer(container) {
876
+ if (!container) return;
877
+
878
+ // 查找容器内的所有内容元素
879
+ const contentElements = container.querySelectorAll('p, div, pre, span, code, table');
880
+
881
+ contentElements.forEach(element => {
882
+ // 设置必要的样式以防止溢出
883
+ element.style.maxWidth = '100%';
884
+ element.style.wordWrap = 'break-word';
885
+ element.style.wordBreak = 'break-word';
886
+ element.style.overflowWrap = 'break-word';
887
+ element.style.boxSizing = 'border-box';
888
+
889
+ // 处理长字符串或代码
890
+ if (element.scrollWidth > element.clientWidth) {
891
+ element.style.whiteSpace = 'pre-wrap';
892
+ }
893
+ });
894
+ }
895
+
896
+ // 调整步骤项布局
897
+ function adjustStepItemsLayout() {
898
+ const stepItems = document.querySelectorAll('.step-item');
899
+ const isMobile = window.innerWidth <= 768;
900
+
901
+ stepItems.forEach(item => {
902
+ const logHeader = item.querySelector('.log-header');
903
+ const contentPreview = item.querySelector('.content-preview');
904
+ const logPrefix = item.querySelector('.log-prefix');
905
+ const timeElement = logPrefix ? logPrefix.querySelector('time') : null;
906
+
907
+ if (isMobile) {
908
+ // 手机布局
909
+ if (contentPreview) {
910
+ contentPreview.style.maxWidth = 'calc(100% - 40px)';
911
+ contentPreview.style.marginLeft = '34px';
912
+ }
913
+
914
+ if (timeElement) {
915
+ timeElement.style.fontSize = '0.7rem';
916
+ }
917
+ } else {
918
+ // 桌面布局
919
+ if (contentPreview) {
920
+ contentPreview.style.maxWidth = '';
921
+ contentPreview.style.marginLeft = '';
922
+ }
923
+
924
+ if (timeElement) {
925
+ timeElement.style.fontSize = '';
926
+ }
927
+ }
928
+ });
929
+ }
930
+
931
+ function getEventIcon(type) {
932
+ switch (type) {
933
+ case 'think': return '<i class="fas fa-brain"></i>';
934
+ case 'tool': return '<i class="fas fa-cog"></i>';
935
+ case 'act': return '<i class="fas fa-wave-square"></i>';
936
+ case 'log': return '<i class="fas fa-file-alt"></i>';
937
+ case 'run': return '<i class="fas fa-play"></i>';
938
+ case 'message': return '<i class="fas fa-comment"></i>';
939
+ case 'complete': return '<i class="fas fa-check"></i>';
940
+ case 'error': return '<i class="fas fa-times"></i>';
941
+ default: return '<i class="fas fa-thumbtack"></i>';
942
+ }
943
+ }
944
+
945
+ function getEventLabel(type) {
946
+ switch (type) {
947
+ case 'think': return 'Thinking';
948
+ case 'tool': return 'Using Tool';
949
+ case 'act': return 'Taking Action';
950
+ case 'log': return 'Log';
951
+ case 'run': return 'Running';
952
+ case 'message': return 'Message';
953
+ case 'complete': return 'Completed';
954
+ case 'error': return 'Error';
955
+ default: return 'Step';
956
+ }
957
+ }
958
+
959
+ function updateTaskStatus(task) {
960
+ const statusBar = document.getElementById('status-bar');
961
+ if (!statusBar) return;
962
+
963
+ if (task.status === 'completed') {
964
+ statusBar.innerHTML = `<span class="status-complete">✅ Task completed</span>`;
965
+
966
+ if (currentEventSource) {
967
+ currentEventSource.close();
968
+ currentEventSource = null;
969
+ }
970
+ } else if (task.status === 'failed') {
971
+ statusBar.innerHTML = `<span class="status-error">❌ Task failed: ${task.error || 'Unknown error'}</span>`;
972
+
973
+ if (currentEventSource) {
974
+ currentEventSource.close();
975
+ currentEventSource = null;
976
+ }
977
+ } else {
978
+ statusBar.innerHTML = `<span class="status-running">⚙️ Task running: ${task.status}</span>`;
979
+ }
980
+ }
981
+
982
+ function showFullImage(imageSrc) {
983
+ let modal = document.getElementById('image-modal');
984
+ if (!modal) {
985
+ modal = document.createElement('div');
986
+ modal.id = 'image-modal';
987
+ modal.className = 'image-modal';
988
+ modal.innerHTML = `
989
+ <span class="close-modal">&times;</span>
990
+ <img src="${imageSrc}" class="modal-content" id="full-image">
991
+ `;
992
+ document.body.appendChild(modal);
993
+
994
+ const closeBtn = modal.querySelector('.close-modal');
995
+ closeBtn.addEventListener('click', () => {
996
+ modal.classList.remove('active');
997
+ });
998
+
999
+ modal.addEventListener('click', (e) => {
1000
+ if (e.target === modal) {
1001
+ modal.classList.remove('active');
1002
+ }
1003
+ });
1004
+ } else {
1005
+ document.getElementById('full-image').src = imageSrc;
1006
+ }
1007
+
1008
+ modal.classList.add('active');
1009
+ }
1010
+
1011
+ function simulateRunPython(filePath) {
1012
+ let modal = document.getElementById('python-modal');
1013
+ if (!modal) {
1014
+ modal = document.createElement('div');
1015
+ modal.id = 'python-modal';
1016
+ modal.className = 'python-modal';
1017
+ modal.innerHTML = `
1018
+ <div class="python-console">
1019
+ <div class="close-modal">&times;</div>
1020
+ <div class="python-output">Loading Python file content...</div>
1021
+ </div>
1022
+ `;
1023
+ document.body.appendChild(modal);
1024
+
1025
+ const closeBtn = modal.querySelector('.close-modal');
1026
+ closeBtn.addEventListener('click', () => {
1027
+ modal.classList.remove('active');
1028
+ });
1029
+ }
1030
+
1031
+ modal.classList.add('active');
1032
+
1033
+ // Load Python file content
1034
+ fetch(filePath)
1035
+ .then(response => response.text())
1036
+ .then(code => {
1037
+ const outputDiv = modal.querySelector('.python-output');
1038
+ outputDiv.innerHTML = '';
1039
+
1040
+ const codeElement = document.createElement('pre');
1041
+ codeElement.textContent = code;
1042
+ codeElement.style.marginBottom = '20px';
1043
+ codeElement.style.padding = '10px';
1044
+ codeElement.style.borderBottom = '1px solid #444';
1045
+ outputDiv.appendChild(codeElement);
1046
+
1047
+ // Add simulation run results
1048
+ const resultElement = document.createElement('div');
1049
+ resultElement.innerHTML = `
1050
+ <div style="color: #4CAF50; margin-top: 10px; margin-bottom: 10px;">
1051
+ > Simulation run output results:</div>
1052
+ <pre style="color: #f8f8f8;">
1053
+ # This is the simulation run output results
1054
+ # Actual run results may vary
1055
+
1056
+ # Running ${filePath.split('/').pop()}...
1057
+ print("Hello from Python Simulated environment!")
1058
+
1059
+ # Code execution completed
1060
+ </pre>
1061
+ `;
1062
+ outputDiv.appendChild(resultElement);
1063
+ })
1064
+ .catch(error => {
1065
+ console.error('Failed to load Python file:', error);
1066
+ const outputDiv = modal.querySelector('.python-output');
1067
+ outputDiv.innerHTML = `File loading error: ${error.message}`;
1068
+ });
1069
+ }
1070
+
1071
+ // Highlight current selected step
1072
+ function highlightStep(stepElement) {
1073
+ // 移除其他步骤的高亮
1074
+ document.querySelectorAll('.step-item').forEach(item => {
1075
+ item.classList.remove('active');
1076
+ });
1077
+
1078
+ // 添加当前步骤的高亮
1079
+ stepElement.classList.add('active');
1080
+
1081
+ // 更新当前步骤信息到结果面板
1082
+ const currentStep = document.getElementById('current-step');
1083
+ if (currentStep) {
1084
+ const type = stepElement.dataset.type;
1085
+ currentStep.setAttribute('data-type', type);
1086
+ }
1087
+ }
1088
+
1089
+ // Toggle history panel display state
1090
+ function toggleHistory() {
1091
+ const historyPanel = document.querySelector('.history-panel');
1092
+ const overlay = document.querySelector('.overlay');
1093
+ const historyToggle = document.querySelector('.history-toggle');
1094
+ const container = document.querySelector('.container');
1095
+
1096
+ if (historyVisible) {
1097
+ // Hide history
1098
+ historyPanel.classList.remove('show');
1099
+ overlay.classList.remove('show');
1100
+ historyToggle.classList.remove('active');
1101
+ container.classList.remove('with-history');
1102
+ } else {
1103
+ // Show history
1104
+ historyPanel.classList.add('show');
1105
+ overlay.classList.add('show');
1106
+ historyToggle.classList.add('active');
1107
+ // Add spacing on large screens
1108
+ if (window.innerWidth > 768) {
1109
+ container.classList.add('with-history');
1110
+ }
1111
+ }
1112
+
1113
+ historyVisible = !historyVisible;
1114
+ }
1115
+
1116
+ // Close history panel on small screens
1117
+ function closeHistoryOnMobile() {
1118
+ if (window.innerWidth <= 768 && historyVisible) {
1119
+ toggleHistory();
1120
+ }
1121
+ }
1122
+
1123
+ // Get status text
1124
+ function getStatusText(status) {
1125
+ switch (status) {
1126
+ case 'pending': return 'Pending';
1127
+ case 'running': return 'Running';
1128
+ case 'completed': return 'Completed';
1129
+ case 'failed': return 'Failed';
1130
+ default: return 'Unknown';
1131
+ }
1132
+ }
1133
+
1134
+ // Initialize interface
1135
+ function initializeInterface() {
1136
+ // 添加历史记录切换逻辑
1137
+ const historyToggle = document.querySelector('.history-toggle');
1138
+ if (historyToggle) {
1139
+ historyToggle.addEventListener('click', toggleHistory);
1140
+ }
1141
+
1142
+ // 添加遮罩层点击关闭历史记录
1143
+ const overlay = document.querySelector('.overlay');
1144
+ if (overlay) {
1145
+ overlay.addEventListener('click', toggleHistory);
1146
+ }
1147
+
1148
+ // 绑定输入框事件
1149
+ const promptInput = document.getElementById('prompt-input');
1150
+ if (promptInput) {
1151
+ promptInput.addEventListener('keydown', (e) => {
1152
+ if (e.key === 'Enter' && !e.shiftKey) {
1153
+ e.preventDefault();
1154
+ createTask();
1155
+ }
1156
+ });
1157
+ }
1158
+
1159
+ // 添加窗口大小调整事件监听
1160
+ window.addEventListener('resize', handleWindowResize);
1161
+
1162
+ // 添加键盘事件监听,用于关闭模态框
1163
+ document.addEventListener('keydown', handleKeyboardEvents);
1164
+
1165
+ // 添加屏幕方向变化监听
1166
+ window.addEventListener('orientationchange', () => {
1167
+ // 延迟执行以确保方向变化完成
1168
+ setTimeout(handleResponsiveLayout, 300);
1169
+ });
1170
+
1171
+ // 阻止页面滚动
1172
+ preventPageScroll();
1173
+
1174
+ // 设置初始布局
1175
+ setupInitialLayout();
1176
+
1177
+ // 加载历史任务
1178
+ loadHistory();
1179
+ }
1180
+
1181
+ // 阻止页面滚动
1182
+ function preventPageScroll() {
1183
+ // 阻止文档滚轮事件,保留容器内滚动
1184
+ document.addEventListener('wheel', function(event) {
1185
+ // 检查是否在可滚动容器内
1186
+ const isInScrollable =
1187
+ event.target.closest('.steps-container') ||
1188
+ event.target.closest('.result-container') ||
1189
+ event.target.closest('.history-panel') ||
1190
+ event.target.closest('.log-body');
1191
+
1192
+ if (!isInScrollable) {
1193
+ event.preventDefault();
1194
+ }
1195
+ }, { passive: false });
1196
+ }
1197
+
1198
+ // 处理窗口大小调整
1199
+ function handleWindowResize() {
1200
+ const container = document.querySelector('.container');
1201
+
1202
+ // 大屏幕上保持历史侧边栏效果,小屏幕上移除
1203
+ if (window.innerWidth > 768 && historyVisible) {
1204
+ container.classList.add('with-history');
1205
+ } else {
1206
+ container.classList.remove('with-history');
1207
+ }
1208
+
1209
+ // 调用综合处理函数
1210
+ handleResponsiveLayout();
1211
+ }
1212
+
1213
+ // 处理键盘事件
1214
+ function handleKeyboardEvents(e) {
1215
+ // ESC键关闭历史面板和模态框
1216
+ if (e.key === 'Escape') {
1217
+ if (historyVisible) {
1218
+ toggleHistory();
1219
+ }
1220
+
1221
+ const imageModal = document.getElementById('image-modal');
1222
+ if (imageModal && imageModal.classList.contains('active')) {
1223
+ imageModal.classList.remove('active');
1224
+ }
1225
+
1226
+ const pythonModal = document.getElementById('python-modal');
1227
+ if (pythonModal && pythonModal.classList.contains('active')) {
1228
+ pythonModal.classList.remove('active');
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ // 设置初始布局
1234
+ function setupInitialLayout() {
1235
+ // 调整步骤项布局
1236
+ adjustStepItemsLayout();
1237
+
1238
+ // 初始化历史面板状态
1239
+ const historyPanel = document.querySelector('.history-panel');
1240
+ if (historyPanel) {
1241
+ historyPanel.classList.remove('show');
1242
+ }
1243
+
1244
+ // 确保结果面板初始隐藏
1245
+ const resultPanel = document.getElementById('result-panel');
1246
+ if (resultPanel) {
1247
+ hideResultPanel();
1248
+ }
1249
+
1250
+ // 手动触发一次响应式布局
1251
+ handleResponsiveLayout();
1252
+ }
1253
+
1254
+ // 当文档加载完成时初始化界面
1255
+ document.addEventListener('DOMContentLoaded', initializeInterface);
static/themes/cyberpunk/static/style.css ADDED
@@ -0,0 +1,2880 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --primary-color: #00eeff;
3
+ --primary-hover: #00c8ff;
4
+ --primary-color-light: rgba(0, 238, 255, 0.1);
5
+ --success-color: #00ff9d;
6
+ --success-color-light: rgba(0, 255, 157, 0.1);
7
+ --error-color: #ff2a6d;
8
+ --error-color-light: rgba(255, 42, 109, 0.1);
9
+ --warning-color: #ffb627;
10
+ --warning-color-light: rgba(255, 182, 39, 0.1);
11
+ --info-color: #05d9e8;
12
+ --info-color-light: rgba(5, 217, 232, 0.1);
13
+ --text-color: rgba(255, 255, 255, 0.9);
14
+ --text-light: rgba(255, 255, 255, 0.6);
15
+ --bg-color: #0a0a1a;
16
+ --panel-bg: rgba(22, 24, 36, 0.9);
17
+ --border-color: rgba(0, 238, 255, 0.6);
18
+ --border-glow: 0 0 15px rgba(0, 238, 255, 0.6), 0 0 25px rgba(0, 238, 255, 0.3);
19
+ --neon-glow: 0 0 15px rgba(0, 238, 255, 0.7), 0 0 25px rgba(0, 238, 255, 0.4);
20
+ --neon-text-glow: 0 0 10px rgba(0, 238, 255, 0.7), 0 0 20px rgba(0, 238, 255, 0.4);
21
+ --secondary-glow: 0 0 12px rgba(255, 42, 109, 0.6), 0 0 20px rgba(255, 42, 109, 0.3);
22
+ --card-bg: rgba(22, 24, 36, 0.7);
23
+ --grid-color: rgba(0, 238, 255, 0.15);
24
+
25
+
26
+ --spacing-xs: 0.25rem;
27
+ --spacing-sm: 0.5rem;
28
+ --spacing-md: 1rem;
29
+ --spacing-lg: 1.5rem;
30
+ --spacing-xl: 2rem;
31
+
32
+
33
+ --font-size-xs: clamp(0.7rem, 2vw, 0.8rem);
34
+ --font-size-sm: clamp(0.8rem, 2vw, 0.9rem);
35
+ --font-size-base: clamp(0.9rem, 2.5vw, 1rem);
36
+ --font-size-md: clamp(1rem, 3vw, 1.1rem);
37
+ --font-size-lg: clamp(1.1rem, 3.5vw, 1.3rem);
38
+ --font-size-xl: clamp(1.3rem, 4vw, 1.5rem);
39
+ --font-size-2xl: clamp(1.5rem, 5vw, 1.8rem);
40
+ --font-size-3xl: clamp(1.8rem, 6vw, 2.2rem);
41
+ --font-size-4xl: clamp(2.2rem, 7vw, 2.8rem);
42
+
43
+
44
+ --border-radius-sm: 4px;
45
+ --border-radius-md: 8px;
46
+ --border-radius-lg: 12px;
47
+
48
+
49
+ --shadow-sm: 0 0 0.5rem rgba(0, 238, 255, 0.2);
50
+ --shadow-md: 0 0 1rem rgba(0, 238, 255, 0.3);
51
+ --shadow-lg: 0 0 1.5rem rgba(0, 238, 255, 0.4);
52
+ }
53
+
54
+ * {
55
+ box-sizing: border-box;
56
+ margin: 0;
57
+ padding: 0;
58
+ }
59
+
60
+ html, body {
61
+ margin: 0;
62
+ padding: 0;
63
+ height: 100%;
64
+ overflow: hidden; /* 防止整个页面滚动 */
65
+ }
66
+
67
+ body {
68
+ font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
69
+ margin: 0;
70
+ padding: 0;
71
+ background-color: #000000;
72
+ color: var(--text-color);
73
+ position: relative;
74
+ overflow-x: hidden;
75
+ font-size: var(--font-size-base);
76
+ line-height: 1.5;
77
+ }
78
+
79
+ body::before {
80
+ display: none;
81
+ }
82
+
83
+ .container {
84
+ display: flex;
85
+ min-height: 100vh;
86
+ min-width: 0;
87
+ width: 100%;
88
+ max-width: 2560px;
89
+ margin: 0 auto;
90
+ padding: var(--spacing-md);
91
+ gap: var(--spacing-md);
92
+ position: relative;
93
+ transition: all 0.3s ease;
94
+ margin-top: 60px;
95
+ min-height: calc(100vh - 70px);
96
+ z-index: 1;
97
+ background-color: #000000;
98
+ }
99
+
100
+ .container.with-result {
101
+
102
+ width: calc(68% - 10px);
103
+ margin-right: auto;
104
+ margin-left: 0;
105
+ }
106
+
107
+ .card {
108
+ background-color: var(--card-bg);
109
+ border-radius: 8px;
110
+ padding: 20px;
111
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
112
+ border: 1px solid var(--border-color);
113
+ }
114
+
115
+ .history-panel {
116
+ width: 200px;
117
+ flex-shrink: 0;
118
+ background-color: var(--panel-bg);
119
+ border-radius: 8px;
120
+ padding: 15px;
121
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
122
+ height: calc(100vh - 80px);
123
+ overflow: auto;
124
+ border: 1px solid var(--border-color);
125
+ }
126
+
127
+ .steps-panel {
128
+ width: 300px;
129
+ flex-shrink: 0;
130
+ background-color: var(--panel-bg);
131
+ border-radius: 8px;
132
+ padding: 15px;
133
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
134
+ height: calc(100vh - 80px);
135
+ overflow: auto;
136
+ border: 1px solid var(--border-color);
137
+ }
138
+
139
+ .steps-container {
140
+ flex: 1;
141
+ width: 100%;
142
+ overflow-y: auto;
143
+ overflow-x: hidden;
144
+ }
145
+
146
+ .main-panel {
147
+ flex: 1;
148
+ display: flex;
149
+ flex-direction: column;
150
+ gap: 10px;
151
+ height: calc(100vh - 80px);
152
+ min-width: 400px;
153
+ position: relative;
154
+ transition: all 0.3s ease;
155
+ z-index: 2;
156
+ background-color: transparent;
157
+ }
158
+
159
+ .task-container {
160
+ flex: 1;
161
+ width: 100%;
162
+ max-width: 100%;
163
+ position: relative;
164
+ display: flex;
165
+ flex-direction: column;
166
+ justify-content: center;
167
+ background-color: #000000;
168
+ border-radius: 8px;
169
+ padding: 15px;
170
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.2);
171
+ overflow: auto;
172
+ transition: width 0.3s ease;
173
+ border: 2px solid transparent !important;
174
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.3) !important;
175
+ position: relative;
176
+ z-index: 1;
177
+ }
178
+
179
+ .task-container::before, .task-container::after {
180
+ content: '';
181
+ position: absolute;
182
+ top: -2px;
183
+ left: -2px;
184
+ right: -2px;
185
+ bottom: -2px;
186
+ z-index: -1;
187
+ background: linear-gradient(90deg,
188
+ var(--primary-color),
189
+ var(--error-color),
190
+ var(--primary-color));
191
+ background-size: 400% 100%;
192
+ animation: borderFlow 8s linear infinite;
193
+ border-radius: inherit;
194
+ }
195
+
196
+ .task-container::after {
197
+ background: var(--bg-color);
198
+ border-radius: inherit;
199
+ box-shadow: inset 0 0 20px rgba(0, 238, 255, 0.2),
200
+ inset 0 0 10px rgba(255, 42, 109, 0.1);
201
+ pointer-events: none;
202
+ }
203
+
204
+ .result-panel {
205
+ width: 31%;
206
+ min-width: 310px;
207
+ max-width: calc(100vw - 20px);
208
+ height: calc(100vh - 85px);
209
+ position: fixed;
210
+ right: 10px;
211
+ top: 70px;
212
+ background-color: rgba(15, 15, 30, 0.95);
213
+ border: 2px solid transparent !important;
214
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.3) !important;
215
+ border-radius: 8px;
216
+ padding: 12px 12px 20px 12px;
217
+ overflow: hidden;
218
+ transition: transform 0.3s ease, opacity 0.3s ease;
219
+ z-index: 10;
220
+ display: flex;
221
+ flex-direction: column;
222
+ opacity: 1;
223
+ box-sizing: border-box;
224
+ }
225
+
226
+ .result-panel::before, .result-panel::after {
227
+ content: '';
228
+ position: absolute;
229
+ top: -2px;
230
+ left: -2px;
231
+ right: -2px;
232
+ bottom: -2px;
233
+ z-index: -1;
234
+ background: linear-gradient(90deg,
235
+ var(--primary-color),
236
+ var(--error-color),
237
+ var(--primary-color));
238
+ background-size: 400% 100%;
239
+ animation: borderFlow 8s linear infinite;
240
+ border-radius: inherit;
241
+ }
242
+
243
+ .result-panel.hidden {
244
+ transform: translateX(calc(100% + 10px));
245
+ opacity: 0;
246
+ pointer-events: none;
247
+ }
248
+
249
+ .result-panel.minimized {
250
+ display: none !important;
251
+ }
252
+
253
+ .result-header {
254
+ display: flex;
255
+ justify-content: space-between;
256
+ align-items: center;
257
+ margin-bottom: 12px;
258
+ padding-bottom: 12px;
259
+ border-bottom: 1px solid rgba(0, 238, 255, 0.2);
260
+ background: linear-gradient(90deg, rgba(15, 15, 30, 0.9), rgba(20, 20, 40, 0.9));
261
+ padding: 15px;
262
+ border-radius: 8px 8px 0 0;
263
+ position: relative;
264
+ overflow: hidden;
265
+ }
266
+
267
+ .result-header::after {
268
+ content: '';
269
+ position: absolute;
270
+ bottom: 0;
271
+ left: 0;
272
+ width: 100%;
273
+ height: 1px;
274
+ background: linear-gradient(90deg,
275
+ transparent,
276
+ rgba(0, 238, 255, 0.4),
277
+ rgba(255, 42, 109, 0.6),
278
+ rgba(0, 238, 255, 0.4),
279
+ transparent
280
+ );
281
+ }
282
+
283
+ .result-header h2 {
284
+ font-size: 18px;
285
+ font-weight: 600;
286
+ color: var(--primary-color);
287
+ margin: 0;
288
+ position: relative;
289
+ text-shadow: 0 0 10px rgba(0, 238, 255, 0.5);
290
+ display: flex;
291
+ align-items: center;
292
+ letter-spacing: 1px;
293
+ animation: none;
294
+ }
295
+
296
+ .result-header h2::before {
297
+ content: '';
298
+ display: inline-block;
299
+ width: 10px;
300
+ height: 10px;
301
+ background-color: var(--primary-color);
302
+ border-radius: 50%;
303
+ margin-right: 10px;
304
+ box-shadow: 0 0 8px var(--primary-color);
305
+ animation: pulse-light 2s infinite;
306
+ }
307
+
308
+ .result-controls {
309
+ display: flex;
310
+ gap: 8px;
311
+ }
312
+
313
+ .minimize-result {
314
+ display: inline-flex;
315
+ width: 28px;
316
+ height: 28px;
317
+ justify-content: center;
318
+ align-items: center;
319
+ border-radius: 4px;
320
+ cursor: pointer;
321
+ user-select: none;
322
+ transition: all 0.2s;
323
+ position: relative;
324
+ background: rgba(255, 255, 255, 0.05);
325
+ border: 1px solid rgba(255, 255, 255, 0.1);
326
+ }
327
+
328
+ .minimize-result:hover {
329
+ background: rgba(255, 255, 255, 0.15);
330
+ transform: scale(1.05);
331
+ box-shadow: 0 0 10px rgba(0, 140, 255, 0.4);
332
+ }
333
+
334
+
335
+ .minimize-result::before,
336
+ .minimize-result::after {
337
+ content: "";
338
+ position: absolute;
339
+ background-color: rgba(255, 255, 255, 0.8);
340
+ transition: all 0.2s;
341
+ }
342
+
343
+
344
+ .minimize-result::before {
345
+ width: 12px;
346
+ height: 12px;
347
+ border: 1px solid rgba(255, 255, 255, 0.8);
348
+ background: transparent;
349
+ }
350
+
351
+
352
+ .minimize-result::after {
353
+ width: 5px;
354
+ height: 5px;
355
+ background-color: rgba(255, 255, 255, 0.8);
356
+ right: 7px;
357
+ bottom: 7px;
358
+ }
359
+
360
+ .result-container {
361
+ width: 100%;
362
+ flex: 1;
363
+ overflow-y: auto;
364
+ overflow-x: hidden;
365
+ margin-top: 0;
366
+ padding: 5px 5px 15px 5px;
367
+ font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
368
+ background-color: transparent;
369
+ color: rgba(255, 255, 255, 0.85);
370
+ max-height: calc(100vh - 200px);
371
+ word-wrap: break-word;
372
+ word-break: break-word;
373
+ box-sizing: border-box;
374
+ position: relative;
375
+ }
376
+
377
+ /* 确保所有内容块被约束在容器内 */
378
+ .result-container * {
379
+ max-width: 100%;
380
+ box-sizing: border-box;
381
+ overflow-wrap: break-word;
382
+ word-wrap: break-word;
383
+ word-break: break-all;
384
+ }
385
+
386
+ .result-container p,
387
+ .result-container div,
388
+ .result-container pre,
389
+ .result-container span {
390
+ white-space: pre-wrap;
391
+ word-wrap: break-word;
392
+ word-break: break-word;
393
+ max-width: 100%;
394
+ margin-bottom: 5px;
395
+ line-height: 1.4;
396
+ box-sizing: border-box;
397
+ }
398
+
399
+ .result-container pre,
400
+ .result-container code {
401
+ white-space: pre-wrap;
402
+ word-wrap: break-word;
403
+ word-break: break-word;
404
+ max-width: 100%;
405
+ background-color: rgba(0, 0, 0, 0.2);
406
+ padding: 5px;
407
+ border-radius: 5px;
408
+ overflow-x: auto;
409
+ box-sizing: border-box;
410
+ }
411
+
412
+ .result-container img {
413
+ max-width: 100%;
414
+ height: auto;
415
+ display: block;
416
+ margin: 5px 0;
417
+ box-sizing: border-box;
418
+ }
419
+
420
+ .result-container table {
421
+ width: 100%;
422
+ border-collapse: collapse;
423
+ margin: 10px 0;
424
+ overflow-x: auto;
425
+ display: block;
426
+ box-sizing: border-box;
427
+ }
428
+
429
+ .result-container th,
430
+ .result-container td {
431
+ border: 1px solid rgba(255, 255, 255, 0.2);
432
+ padding: 5px;
433
+ text-align: left;
434
+ box-sizing: border-box;
435
+ }
436
+
437
+
438
+ .search-result-item {
439
+ padding: 10px;
440
+ border-bottom: 1px solid #eee;
441
+ cursor: pointer;
442
+ }
443
+
444
+ .search-result-item:hover {
445
+ background-color: #f0f0f0;
446
+ }
447
+
448
+ .search-result-title {
449
+ font-weight: 500;
450
+ color: #1a0dab;
451
+ margin-bottom: 3px;
452
+ }
453
+
454
+ .search-result-url {
455
+ color: #006621;
456
+ font-size: 0.8rem;
457
+ margin-bottom: 3px;
458
+ }
459
+
460
+ .search-result-description {
461
+ color: #545454;
462
+ font-size: 0.9rem;
463
+ }
464
+
465
+
466
+ .search-box {
467
+ display: flex;
468
+ align-items: center;
469
+ margin-bottom: 10px;
470
+ padding: 8px;
471
+ background-color: #f5f5f5;
472
+ border-radius: 4px;
473
+ border: 1px solid #e0e0e0;
474
+ }
475
+
476
+ .search-box-icon {
477
+ color: #777;
478
+ margin-right: 8px;
479
+ }
480
+
481
+ .search-input {
482
+ flex: 1;
483
+ border: none;
484
+ background: transparent;
485
+ outline: none;
486
+ font-size: 14px;
487
+ color: #333;
488
+ }
489
+
490
+ .search-box .search-button {
491
+ background-color: #f5f5f5;
492
+ color: #777;
493
+ border: none;
494
+ padding: 4px 8px;
495
+ border-radius: 4px;
496
+ cursor: pointer;
497
+ font-size: 14px;
498
+ }
499
+
500
+ .search-box .search-button:hover {
501
+ background-color: #e0e0e0;
502
+ }
503
+
504
+ .task-list {
505
+ margin-top: 10px;
506
+ max-height: calc(100% - 40px);
507
+ overflow-y: auto;
508
+ overflow-x: hidden;
509
+ }
510
+
511
+
512
+ .welcome-message {
513
+ display: flex;
514
+ flex-direction: column;
515
+ justify-content: center;
516
+ align-items: center;
517
+ text-align: center;
518
+ color: var(--text-light);
519
+ padding: 40px 20px;
520
+ width: 100%;
521
+ height: 100%;
522
+ min-height: 400px;
523
+ position: relative;
524
+ margin: auto 0;
525
+ background: transparent;
526
+ border: none;
527
+ box-shadow: none;
528
+ border: 2px solid transparent !important;
529
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.3) !important;
530
+ position: relative;
531
+ overflow: hidden;
532
+ z-index: 1;
533
+ max-width: 100%;
534
+ }
535
+
536
+ @media screen and (max-width: 768px) {
537
+ .welcome-message {
538
+ min-height: 350px; padding: 30px 15px;
539
+ }
540
+ .title {
541
+ font-size: 2.5rem; letter-spacing: 2px;
542
+ }
543
+ .subtitle {
544
+ font-size: 1.2rem; margin-bottom: 20px;
545
+ }
546
+ .description {
547
+ font-size: 1rem; line-height: 1.5; margin-bottom: 30px;
548
+ }
549
+ .cta-button {
550
+ font-size: 0.9rem; padding: 10px 20px;
551
+ }
552
+ .emoji {
553
+ font-size: 2rem;
554
+ }
555
+ .step-item .log-header {
556
+ flex-wrap: wrap; padding: 4px 8px;
557
+ }
558
+ .log-prefix {
559
+ width: 100%; margin-bottom: 5px;
560
+ }
561
+ .content-preview {
562
+ width: calc(100% - 40px); max-width: none; margin-left: 34px; margin-bottom: 5px;
563
+ }
564
+ .step-controls {
565
+ position: absolute; top: 10px; right: 10px;
566
+ }
567
+ .log-prefix time {
568
+ font-size: 10px; padding: 1px 4px;
569
+ }
570
+ .log-prefix-icon {
571
+ width: 22px; height: 22px; font-size: 12px;
572
+ }
573
+ .title-text {
574
+ font-size: clamp(1.5rem, 6vw, 2.5rem); letter-spacing: 0.03em; margin: 0.3em 0; transform: scale(0.9);
575
+ }
576
+ .subtitle-text {
577
+ font-size: 1.2rem; letter-spacing: 3px; margin: 10px 0;
578
+ }
579
+ .command-text {
580
+ font-size: 0.7rem; letter-spacing: 1px; padding: 10px 0;
581
+ }
582
+ }
583
+
584
+ @media screen and (max-width: 480px) {
585
+ .welcome-message {
586
+ min-height: 300px; padding: 30px 15px;
587
+ }
588
+ .title {
589
+ font-size: 3.5rem; margin-bottom: 0.8rem;
590
+ }
591
+ .subtitle {
592
+ font-size: 1.3rem; margin-bottom: 1rem;
593
+ }
594
+ .description {
595
+ font-size: 0.9rem; line-height: 1.6; margin-bottom: 2rem;
596
+ }
597
+ .cta-button {
598
+ padding: 0.7rem 2rem; font-size: 0.9rem; border-radius: 20px;
599
+ }
600
+ .emoji {
601
+ font-size: 1.5rem;
602
+ }
603
+ .hero-section {
604
+ padding: 1.5rem 1rem;
605
+ }
606
+ .result-panel {
607
+ width: 90%; min-width: auto; right: 5%; left: 5%;
608
+ }
609
+ .step-item .log-header {
610
+ padding: 8px;
611
+ }
612
+ .log-prefix time {
613
+ font-size: 0.8em; padding: 2px 4px;
614
+ }
615
+ .log-prefix-icon {
616
+ width: 22px; height: 22px; font-size: 0.8em;
617
+ }
618
+ .title-text {
619
+ font-size: clamp(1.2rem, 5.5vw, 2rem); letter-spacing: 0.02em; transform: scale(0.85);
620
+ }
621
+ .subtitle-text {
622
+ font-size: 1rem; letter-spacing: 2px;
623
+ }
624
+ }
625
+
626
+ .welcome-message::before {
627
+ filter: blur(1px);
628
+ animation: borderFlow 12s linear infinite;
629
+ display: none;
630
+ }
631
+
632
+ .welcome-message::after {
633
+ background: rgba(10, 10, 26, 0.7);
634
+ box-shadow: inset 0 0 30px rgba(0, 238, 255, 0.3),
635
+ inset 0 0 15px rgba(255, 42, 109, 0.2);
636
+ animation: innerGlow 5s ease-in-out infinite alternate;
637
+ display: none;
638
+ }
639
+
640
+ .welcome-message h1 {
641
+ font-size: 2.5rem;
642
+ margin-bottom: 20px;
643
+ color: var(--text-color);
644
+ font-weight: 600;
645
+ text-shadow: var(--neon-text-glow);
646
+ }
647
+
648
+ .logo-animation {
649
+ margin-bottom: 10px;
650
+ animation: none;
651
+ }
652
+
653
+ .welcome-logo {
654
+ width: min(320px, 90vw);
655
+ height: auto;
656
+ filter: drop-shadow(0 0 0.8em rgba(0, 238, 255, 0.7));
657
+ transition: all 0.3s ease;
658
+ margin-bottom: 5px;
659
+ animation: none;
660
+ }
661
+
662
+ .welcome-logo:hover {
663
+ transform: none;
664
+ filter: drop-shadow(0 0 10px rgba(0, 238, 255, 0.6));
665
+ }
666
+
667
+ .animated-text {
668
+ font-size: 1.8rem;
669
+ margin-bottom: 16px;
670
+ color: var(--primary-color);
671
+ animation: fadeIn 1s ease-in-out;
672
+ animation-delay: 0.3s;
673
+ animation-fill-mode: both;
674
+ text-shadow: var(--neon-text-glow);
675
+ }
676
+
677
+ .animated-subtext {
678
+ font-size: 0.9rem;
679
+ color: var(--text-light);
680
+ animation: fadeIn 1s ease-in-out;
681
+ animation-delay: 0.6s;
682
+ animation-fill-mode: both;
683
+ position: relative;
684
+ overflow: hidden;
685
+ }
686
+
687
+ .animated-subtext::after {
688
+ content: '';
689
+ position: absolute;
690
+ bottom: 0;
691
+ left: 0;
692
+ width: 100%;
693
+ height: 1px;
694
+ background: linear-gradient(90deg,
695
+ transparent,
696
+ rgba(0, 238, 255, 0.4),
697
+ rgba(255, 42, 109, 0.6),
698
+ rgba(0, 238, 255, 0.4),
699
+ transparent
700
+ );
701
+ animation: shimmer 3s infinite;
702
+ }
703
+
704
+ @keyframes shimmer {
705
+ 0% { transform: translateX(-100%); }
706
+ 100% { transform: translateX(100%); }
707
+ }
708
+
709
+ @keyframes pulse {
710
+ 0% {
711
+ transform: scale(1);
712
+ }
713
+ 50% {
714
+ transform: scale(1.05);
715
+ filter: drop-shadow(0 0 1.5rem rgba(0, 238, 255, 0.8));
716
+ }
717
+ 100% {
718
+ transform: scale(1);
719
+ }
720
+ }
721
+
722
+ @keyframes fadeIn {
723
+ from {
724
+ opacity: 0;
725
+ transform: translateY(0.8em);
726
+ }
727
+ to {
728
+ opacity: 1;
729
+ transform: translateY(0);
730
+ }
731
+ }
732
+
733
+ @keyframes titleShadow {
734
+ 0%, 100% {
735
+ filter: drop-shadow(0 0 8px rgba(0, 238, 255, 0.3));
736
+ }
737
+ 50% {
738
+ filter: drop-shadow(0 0 12px rgba(255, 42, 109, 0.4));
739
+ }
740
+ }
741
+
742
+
743
+ .highlight-text {
744
+ background: linear-gradient(135deg, #00eeff 0%, #01beff 50%, #0047e1 100%);
745
+ -webkit-background-clip: text;
746
+ background-clip: text;
747
+ -webkit-text-fill-color: transparent;
748
+ font-weight: 600;
749
+ letter-spacing: 0.5px;
750
+ text-shadow: 0 0 8px rgba(0, 238, 255, 0.6), 0 0 15px rgba(0, 71, 225, 0.4);
751
+ }
752
+
753
+
754
+ .login-btn {
755
+ background: linear-gradient(135deg, rgba(0, 238, 255, 0.8), rgba(0, 71, 225, 0.8));
756
+ color: white;
757
+ padding: 10px 24px;
758
+ border-radius: 4px;
759
+ font-weight: 500;
760
+ font-size: 14px;
761
+ transition: all 0.25s ease;
762
+ display: flex;
763
+ align-items: center;
764
+ gap: 8px;
765
+ border: none;
766
+ cursor: pointer;
767
+ text-decoration: none;
768
+ box-shadow: 0 4px 15px rgba(5, 117, 230, 0.2);
769
+ }
770
+
771
+ .login-btn:hover {
772
+ background: linear-gradient(135deg, #0468C8, #0086E8);
773
+ transform: translateY(-2px);
774
+ box-shadow: 0 6px 20px rgba(5, 117, 230, 0.3);
775
+ }
776
+
777
+ .login-btn:active {
778
+ transform: translateY(0px);
779
+ box-shadow: 0 2px 10px rgba(5, 117, 230, 0.15);
780
+ }
781
+
782
+
783
+ .send-btn {
784
+ padding: 12px 30px;
785
+ background: linear-gradient(135deg, rgba(0, 238, 255, 0.8), rgba(0, 71, 225, 0.8));
786
+ color: white;
787
+ border: 2px solid transparent;
788
+ border-radius: 4px;
789
+ cursor: pointer;
790
+ font-size: 15px;
791
+ font-weight: 500;
792
+ letter-spacing: 1px;
793
+ transition: all 0.25s ease;
794
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.3);
795
+ text-transform: uppercase;
796
+ position: relative;
797
+ overflow: hidden;
798
+ z-index: 1;
799
+ }
800
+
801
+ .send-btn::before {
802
+ content: '';
803
+ position: absolute;
804
+ top: -2px;
805
+ left: -2px;
806
+ right: -2px;
807
+ bottom: -2px;
808
+ background: linear-gradient(90deg,
809
+ var(--primary-color),
810
+ var(--error-color),
811
+ var(--primary-color));
812
+ background-size: 300% 100%;
813
+ z-index: -1;
814
+ animation: buttonGlow 6s linear infinite;
815
+ opacity: 0.9;
816
+ }
817
+
818
+ .send-btn::after {
819
+ content: '';
820
+ position: absolute;
821
+ top: 50%;
822
+ left: -100%;
823
+ width: 70%;
824
+ height: 100%;
825
+ background: linear-gradient(90deg,
826
+ transparent,
827
+ rgba(255, 255, 255, 0.2),
828
+ transparent);
829
+ transform: skewX(-25deg) translateY(-50%);
830
+ animation: buttonShine 4s infinite;
831
+ }
832
+
833
+ @keyframes buttonShine {
834
+ 0% {
835
+ left: -100%;
836
+ }
837
+ 20%, 100% {
838
+ left: 200%;
839
+ }
840
+ }
841
+
842
+ @keyframes buttonGlow {
843
+ 0% {
844
+ background-position: 0% 0;
845
+ }
846
+ 100% {
847
+ background-position: 300% 0;
848
+ }
849
+ }
850
+
851
+ .task-card {
852
+ background: var(--card-bg);
853
+ padding: 12px 15px;
854
+ margin-bottom: 10px;
855
+ border-radius: 4px;
856
+ cursor: pointer;
857
+ border: 1px solid var(--border-color);
858
+ transition: all 0.2s;
859
+ }
860
+
861
+ .task-card:hover {
862
+ transform: translateY(-2px);
863
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
864
+ border-color: var(--primary-color);
865
+ }
866
+
867
+ .task-card.active {
868
+ border-left: 3px solid var(--primary-color);
869
+ background-color: rgba(0, 238, 255, 0.05);
870
+ }
871
+
872
+ .status-pending {
873
+ color: var(--text-light);
874
+ }
875
+
876
+ .status-running {
877
+ color: var(--primary-color);
878
+ }
879
+
880
+ .status-completed {
881
+ color: var(--success-color);
882
+ }
883
+
884
+ .status-failed {
885
+ color: var(--error-color);
886
+ }
887
+
888
+ .status-text {
889
+ margin-left: 5px;
890
+ position: relative;
891
+ color: var(--primary-color) !important;
892
+ font-weight: 600;
893
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
894
+ text-shadow: 0 0 5px rgba(0, 238, 255, 0.4);
895
+ letter-spacing: 0.5px;
896
+ }
897
+
898
+ .status-text::after {
899
+ content: '|';
900
+ position: absolute;
901
+ right: -12px;
902
+ color: var(--primary-color);
903
+ animation: blink 1s infinite;
904
+ text-shadow: 0 0 8px rgba(0, 238, 255, 0.6);
905
+ }
906
+
907
+ @keyframes blink {
908
+ 0%, 100% {
909
+ opacity: 1;
910
+ }
911
+ 50% {
912
+ opacity: 0;
913
+ }
914
+ }
915
+
916
+ .step-item {
917
+ padding: 0;
918
+ background: var(--card-bg);
919
+ border: 1px solid var(--border-color);
920
+ border-radius: 4px;
921
+ width: 100%;
922
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.1);
923
+ margin-bottom: 2px;
924
+ opacity: 1;
925
+ transform: none;
926
+ overflow: hidden;
927
+ transition: all 0.3s ease;
928
+ display: flex;
929
+ flex-direction: column;
930
+ }
931
+
932
+ .step-item .log-header {
933
+ display: flex;
934
+ justify-content: space-between;
935
+ align-items: center;
936
+ padding: 4px 8px;
937
+ cursor: pointer;
938
+ background-color: rgba(15, 15, 30, 0.8);
939
+ transition: all 0.3s ease;
940
+ color: #ffffff !important;
941
+ position: relative;
942
+ overflow: hidden;
943
+ width: 100%;
944
+ border: 2px solid var(--border-color);
945
+ border-radius: 4px 4px 0 0;
946
+ z-index: 1;
947
+ }
948
+
949
+
950
+ .step-item .log-header::before {
951
+ display: none;
952
+ }
953
+
954
+
955
+ .step-item.think .log-header {
956
+ background-color: rgba(5, 217, 232, 0.15);
957
+ border-left: 3px solid var(--info-color);
958
+ color: #ffffff !important;
959
+ }
960
+
961
+ .step-item.tool .log-header {
962
+ background-color: rgba(255, 182, 39, 0.15);
963
+ border-left: 3px solid var(--warning-color);
964
+ color: #ffffff !important;
965
+ }
966
+
967
+ .step-item.act .log-header {
968
+ background-color: rgba(0, 238, 255, 0.15);
969
+ border-left: 3px solid var(--primary-color);
970
+ color: #ffffff !important;
971
+ }
972
+
973
+ .step-item.log .log-header {
974
+ background-color: rgba(15, 15, 30, 0.5);
975
+ border-left: 3px solid var(--border-color);
976
+ color: #ffffff !important;
977
+ }
978
+
979
+
980
+ .step-item .log-header::after {
981
+ display: none;
982
+ }
983
+
984
+ .log-prefix {
985
+ display: flex;
986
+ align-items: center;
987
+ gap: 6px;
988
+ font-size: 12px;
989
+ color: #ffffff !important;
990
+ flex: 0 0 auto;
991
+ position: relative;
992
+ }
993
+
994
+
995
+ .step-item .log-header .log-prefix {
996
+ position: relative;
997
+ z-index: 2;
998
+ }
999
+
1000
+
1001
+ .step-item.think .log-header .log-prefix span:not(.log-prefix-icon):not(time),
1002
+ .step-item.tool .log-header .log-prefix span:not(.log-prefix-icon):not(time),
1003
+ .step-item.act .log-header .log-prefix span:not(.log-prefix-icon):not(time),
1004
+ .step-item.log .log-header .log-prefix span:not(.log-prefix-icon):not(time) {
1005
+ background: linear-gradient(90deg, #00eeff, #7700ff, #ff00c8, #00eeff);
1006
+ -webkit-background-clip: text;
1007
+ background-clip: text;
1008
+ color: transparent !important;
1009
+ background-size: 300% 100%;
1010
+ animation: textGradient 6s linear infinite;
1011
+ font-weight: bold;
1012
+ padding: 0 3px;
1013
+ }
1014
+
1015
+
1016
+ @keyframes textGradient {
1017
+ 0% {
1018
+ background-position: 0% 50%;
1019
+ }
1020
+ 50% {
1021
+ background-position: 100% 50%;
1022
+ }
1023
+ 100% {
1024
+ background-position: 0% 50%;
1025
+ }
1026
+ }
1027
+
1028
+
1029
+ .log-prefix time {
1030
+ font-weight: 500;
1031
+ color: var(--primary-color);
1032
+ background-color: rgba(0, 238, 255, 0.1);
1033
+ padding: 2px 6px;
1034
+ border-radius: 4px;
1035
+ font-size: 11px;
1036
+ display: inline-block;
1037
+ white-space: nowrap;
1038
+ background-clip: padding-box;
1039
+ -webkit-background-clip: padding-box;
1040
+ }
1041
+
1042
+ .step-item.think .log-header {
1043
+ background-color: rgba(5, 217, 232, 0.15);
1044
+ border-left: 3px solid var(--info-color);
1045
+ color: #ffffff !important;
1046
+ }
1047
+
1048
+ .step-item.tool .log-header {
1049
+ background-color: rgba(255, 182, 39, 0.15);
1050
+ border-left: 3px solid var(--warning-color);
1051
+ color: #ffffff !important;
1052
+ }
1053
+
1054
+ .step-item.act .log-header {
1055
+ background-color: rgba(0, 238, 255, 0.15);
1056
+ border-left: 3px solid var(--primary-color);
1057
+ color: #ffffff !important;
1058
+ }
1059
+
1060
+ .step-item.log .log-header {
1061
+ background-color: rgba(15, 15, 30, 0.5);
1062
+ border-left: 3px solid var(--border-color);
1063
+ color: #ffffff !important;
1064
+ }
1065
+
1066
+ .log-prefix {
1067
+ display: flex;
1068
+ align-items: center;
1069
+ gap: 6px;
1070
+ font-size: 12px;
1071
+ color: #ffffff !important;
1072
+ flex: 0 0 auto;
1073
+ }
1074
+
1075
+ .log-prefix time {
1076
+ font-weight: 500;
1077
+ color: var(--primary-color);
1078
+ background-color: rgba(0, 238, 255, 0.1);
1079
+ padding: 2px 6px;
1080
+ border-radius: 4px;
1081
+ font-size: 11px;
1082
+ display: inline-block;
1083
+ white-space: nowrap;
1084
+ }
1085
+
1086
+ .log-prefix-icon {
1087
+ display: inline-flex;
1088
+ width: 26px;
1089
+ height: 26px;
1090
+ background: rgba(0, 238, 255, 0.1);
1091
+ border-radius: 6px;
1092
+ align-items: center;
1093
+ justify-content: center;
1094
+ font-size: 14px;
1095
+ flex: 0 0 auto;
1096
+ position: relative;
1097
+ z-index: 2;
1098
+ }
1099
+
1100
+ .content-preview {
1101
+ margin-left: 4px;
1102
+ white-space: nowrap;
1103
+ overflow: hidden;
1104
+ text-overflow: ellipsis;
1105
+ flex: 1;
1106
+ opacity: 0.9;
1107
+ font-size: 0.9em;
1108
+ color: #ffffff !important;
1109
+ min-width: 0;
1110
+ padding-right: 8px;
1111
+ position: relative;
1112
+ z-index: 2;
1113
+ }
1114
+
1115
+ .step-item .log-body {
1116
+ display: none;
1117
+ padding: 10px;
1118
+ background-color: rgba(15, 15, 30, 0.6);
1119
+ color: #ffffff !important;
1120
+ border-top: 1px solid var(--border-color);
1121
+ }
1122
+
1123
+ .step-controls {
1124
+ display: flex;
1125
+ }
1126
+
1127
+ .minimize-btn {
1128
+ display: inline-flex;
1129
+ width: 18px;
1130
+ height: 18px;
1131
+ justify-content: center;
1132
+ align-items: center;
1133
+ background: rgba(10, 10, 26, 0.6);
1134
+ border: 1px solid var(--border-color);
1135
+ border-radius: 4px;
1136
+ cursor: pointer;
1137
+ user-select: none;
1138
+ color: var(--primary-color);
1139
+ transition: all 0.2s;
1140
+ font-size: 10px;
1141
+ }
1142
+
1143
+ .minimize-btn:hover {
1144
+ background: rgba(0, 238, 255, 0.1);
1145
+ color: var(--text-color);
1146
+ box-shadow: 0 0 8px rgba(0, 238, 255, 0.3);
1147
+ }
1148
+
1149
+ .step-item .log-body {
1150
+ display: none;
1151
+ padding: 10px;
1152
+ background-color: rgba(15, 15, 30, 0.6);
1153
+ color: var(--text-color);
1154
+ border-top: 1px solid var(--border-color);
1155
+ }
1156
+
1157
+
1158
+ .step-item pre {
1159
+ margin: 0;
1160
+ white-space: pre-wrap;
1161
+ word-break: break-word;
1162
+ font-size: 0.95em;
1163
+ line-height: 1.5;
1164
+ padding: 8px;
1165
+ border-radius: 4px;
1166
+ background: rgba(10, 10, 26, 0.7);
1167
+ color: #ffffff !important;
1168
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
1169
+ box-shadow: inset 0 0 10px rgba(0, 238, 255, 0.1);
1170
+ border: 1px solid var(--border-color);
1171
+ }
1172
+
1173
+ .step-item pre.think,
1174
+ .step-item pre.tool,
1175
+ .step-item pre.act,
1176
+ .step-item pre.result,
1177
+ .step-item pre.error {
1178
+ color: #ffffff !important;
1179
+ }
1180
+
1181
+
1182
+ .step-circle {
1183
+ width: 30px;
1184
+ height: 30px;
1185
+ border-radius: 50%;
1186
+ background: linear-gradient(135deg, rgba(0, 238, 255, 0.8), rgba(255, 42, 109, 0.8));
1187
+ color: white;
1188
+ display: flex;
1189
+ align-items: center;
1190
+ justify-content: center;
1191
+ font-weight: bold;
1192
+ font-size: 1em;
1193
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.4);
1194
+ z-index: 2;
1195
+ flex-shrink: 0;
1196
+ text-shadow: 0 0 5px rgba(0, 238, 255, 0.5);
1197
+ border: 1px solid rgba(0, 238, 255, 0.5);
1198
+ position: relative;
1199
+ overflow: hidden;
1200
+ }
1201
+
1202
+ .step-circle::before {
1203
+ content: '';
1204
+ position: absolute;
1205
+ width: 100%;
1206
+ height: 100%;
1207
+ background: radial-gradient(circle at 30% 30%, rgba(0, 238, 255, 0.4), transparent 70%);
1208
+ z-index: -1;
1209
+ }
1210
+
1211
+ .step-item.think .log-header {
1212
+ background-color: rgba(5, 217, 232, 0.15);
1213
+ border-left: 3px solid var(--info-color);
1214
+ color: #ffffff !important;
1215
+ }
1216
+
1217
+ .step-item.tool .log-header {
1218
+ background-color: rgba(255, 182, 39, 0.15);
1219
+ border-left: 3px solid var(--warning-color);
1220
+ color: #ffffff !important;
1221
+ }
1222
+
1223
+ .step-item.act .log-header {
1224
+ background-color: rgba(0, 238, 255, 0.15);
1225
+ border-left: 3px solid var(--primary-color);
1226
+ color: #ffffff !important;
1227
+ }
1228
+
1229
+ .step-item.log .log-header {
1230
+ background-color: rgba(15, 15, 30, 0.5);
1231
+ border-left: 3px solid var(--border-color);
1232
+ color: #ffffff !important;
1233
+ }
1234
+
1235
+ .step-item.expanded .log-body {
1236
+ display: block;
1237
+ }
1238
+
1239
+ .step-item pre.think {
1240
+ background: rgba(5, 217, 232, 0.1);
1241
+ border-left: 4px solid var(--info-color);
1242
+ color: var(--text-color);
1243
+ }
1244
+
1245
+ .step-item pre.tool {
1246
+ background: rgba(255, 182, 39, 0.1);
1247
+ border-left: 4px solid var(--warning-color);
1248
+ color: var(--text-color);
1249
+ }
1250
+
1251
+ .step-item pre.act {
1252
+ background: rgba(0, 238, 255, 0.1);
1253
+ border-left: 4px solid var(--primary-color);
1254
+ color: var(--text-color);
1255
+ }
1256
+
1257
+ .step-item pre.result {
1258
+ background: rgba(0, 255, 157, 0.1);
1259
+ border-left: 4px solid var(--success-color);
1260
+ color: var(--text-color);
1261
+ }
1262
+
1263
+ .step-item pre.error {
1264
+ background: rgba(255, 42, 109, 0.1);
1265
+ border-left: 4px solid var(--error-color);
1266
+ color: var(--text-color);
1267
+ }
1268
+
1269
+ .loading {
1270
+ padding: 15px;
1271
+ color: #666;
1272
+ text-align: center;
1273
+ }
1274
+
1275
+ .ping {
1276
+ color: #ccc;
1277
+ text-align: center;
1278
+ margin: 5px 0;
1279
+ height: 10px;
1280
+ display: block;
1281
+ }
1282
+
1283
+ .error {
1284
+ color: #dc3545;
1285
+ padding: 10px;
1286
+ background: #ffe6e6;
1287
+ border-radius: 4px;
1288
+ margin: 10px 0;
1289
+ }
1290
+
1291
+ .complete {
1292
+ color: #28a745;
1293
+ padding: 10px;
1294
+ background: #e6ffe6;
1295
+ border-radius: 4px;
1296
+ margin: 10px 0;
1297
+ }
1298
+
1299
+ .info {
1300
+ color: #17a2b8;
1301
+ padding: 10px;
1302
+ background: #e3f2fd;
1303
+ border-radius: 4px;
1304
+ margin: 10px 0;
1305
+ }
1306
+
1307
+
1308
+ .step-divider {
1309
+ display: flex;
1310
+ align-items: center;
1311
+ width: 100%;
1312
+ margin: 15px 0;
1313
+ position: relative;
1314
+ }
1315
+
1316
+ .step-circle {
1317
+ width: 36px;
1318
+ height: 36px;
1319
+ border-radius: 50%;
1320
+ background-color: var(--primary-color);
1321
+ color: white;
1322
+ display: flex;
1323
+ align-items: center;
1324
+ justify-content: center;
1325
+ font-weight: bold;
1326
+ font-size: 1.2em;
1327
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
1328
+ z-index: 2;
1329
+ flex-shrink: 0;
1330
+ }
1331
+
1332
+
1333
+ .file-interaction {
1334
+ margin-top: 15px;
1335
+ padding: 15px;
1336
+ border-radius: 8px;
1337
+ background-color: rgba(10, 10, 26, 0.7);
1338
+ border: 1px solid var(--border-color);
1339
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
1340
+ position: relative;
1341
+ overflow: hidden;
1342
+ z-index: 1;
1343
+ }
1344
+
1345
+ .file-interaction::before {
1346
+ content: '';
1347
+ position: absolute;
1348
+ top: -2px;
1349
+ left: -2px;
1350
+ right: -2px;
1351
+ bottom: -2px;
1352
+ z-index: -1;
1353
+ background: linear-gradient(90deg,
1354
+ var(--primary-color),
1355
+ var(--error-color),
1356
+ var(--primary-color));
1357
+ background-size: 400% 100%;
1358
+ animation: borderFlow 8s linear infinite;
1359
+ border-radius: inherit;
1360
+ opacity: 0.6;
1361
+ }
1362
+
1363
+ .file-interaction::after {
1364
+ content: '';
1365
+ position: absolute;
1366
+ top: 2px;
1367
+ left: 2px;
1368
+ right: 2px;
1369
+ bottom: 2px;
1370
+ background: rgba(10, 10, 26, 0.8);
1371
+ border-radius: inherit;
1372
+ z-index: -1;
1373
+ box-shadow: inset 0 0 20px rgba(0, 238, 255, 0.2),
1374
+ inset 0 0 10px rgba(255, 42, 109, 0.1);
1375
+ }
1376
+
1377
+ .download-link {
1378
+ display: inline-block;
1379
+ padding: 10px 20px;
1380
+ background: linear-gradient(135deg, rgba(0, 238, 255, 0.8), rgba(0, 71, 225, 0.8));
1381
+ color: white;
1382
+ text-decoration: none;
1383
+ border-radius: 4px;
1384
+ font-size: 0.95em;
1385
+ font-weight: 500;
1386
+ letter-spacing: 1px;
1387
+ transition: all 0.25s ease;
1388
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.3);
1389
+ position: relative;
1390
+ overflow: hidden;
1391
+ border: 1px solid transparent;
1392
+ text-transform: uppercase;
1393
+ z-index: 1;
1394
+ }
1395
+
1396
+ .download-link::before {
1397
+ content: '';
1398
+ position: absolute;
1399
+ top: -2px;
1400
+ left: -2px;
1401
+ right: -2px;
1402
+ bottom: -2px;
1403
+ background: linear-gradient(90deg,
1404
+ var(--primary-color),
1405
+ var(--error-color),
1406
+ var(--primary-color));
1407
+ background-size: 300% 100%;
1408
+ z-index: -1;
1409
+ animation: buttonGlow 6s linear infinite;
1410
+ opacity: 0.9;
1411
+ border-radius: 4px;
1412
+ }
1413
+
1414
+ .download-link::after {
1415
+ content: '';
1416
+ position: absolute;
1417
+ top: 50%;
1418
+ left: -100%;
1419
+ width: 70%;
1420
+ height: 100%;
1421
+ background: linear-gradient(90deg,
1422
+ transparent,
1423
+ rgba(255, 255, 255, 0.2),
1424
+ transparent);
1425
+ transform: skewX(-25deg) translateY(-50%);
1426
+ animation: buttonShine 4s infinite;
1427
+ }
1428
+
1429
+ .download-link:hover {
1430
+ background: linear-gradient(135deg, rgba(0, 238, 255, 1), rgba(0, 71, 225, 1));
1431
+ transform: translateY(-2px) scale(1.03);
1432
+ box-shadow: 0 0 25px rgba(0, 238, 255, 0.5), 0 0 5px rgba(255, 42, 109, 0.3);
1433
+ letter-spacing: 1.5px;
1434
+ color: white;
1435
+ }
1436
+
1437
+ .preview-image {
1438
+ max-width: 100%;
1439
+ max-height: 200px;
1440
+ margin-bottom: 10px;
1441
+ border-radius: 4px;
1442
+ cursor: pointer;
1443
+ transition: all 0.3s ease;
1444
+ border: 1px solid var(--border-color);
1445
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.2);
1446
+ }
1447
+
1448
+ .preview-image:hover {
1449
+ transform: scale(1.03);
1450
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.5), 0 0 10px rgba(255, 42, 109, 0.3);
1451
+ border-color: var(--primary-color);
1452
+ }
1453
+
1454
+ .audio-player {
1455
+ display: flex;
1456
+ flex-direction: column;
1457
+ gap: 10px;
1458
+ margin: 15px 0;
1459
+ }
1460
+
1461
+ .audio-player audio {
1462
+ width: 100%;
1463
+ margin-bottom: 10px;
1464
+ border-radius: 4px;
1465
+ background: rgba(10, 10, 26, 0.7);
1466
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.2);
1467
+ }
1468
+
1469
+ .run-button {
1470
+ display: inline-block;
1471
+ padding: 10px 20px;
1472
+ background: linear-gradient(135deg, rgba(0, 255, 157, 0.8), rgba(0, 180, 100, 0.8));
1473
+ color: white;
1474
+ border: none;
1475
+ border-radius: 4px;
1476
+ cursor: pointer;
1477
+ font-size: 0.95em;
1478
+ font-weight: 500;
1479
+ letter-spacing: 1px;
1480
+ margin-right: 10px;
1481
+ transition: all 0.25s ease;
1482
+ box-shadow: 0 0 15px rgba(0, 255, 157, 0.3);
1483
+ position: relative;
1484
+ overflow: hidden;
1485
+ text-transform: uppercase;
1486
+ z-index: 1;
1487
+ }
1488
+
1489
+ .run-button::before {
1490
+ content: '';
1491
+ position: absolute;
1492
+ top: -2px;
1493
+ left: -2px;
1494
+ right: -2px;
1495
+ bottom: -2px;
1496
+ background: linear-gradient(90deg,
1497
+ var(--success-color),
1498
+ var(--primary-color),
1499
+ var(--success-color));
1500
+ background-size: 300% 100%;
1501
+ z-index: -1;
1502
+ animation: buttonGlow 6s linear infinite;
1503
+ opacity: 0.9;
1504
+ border-radius: 4px;
1505
+ }
1506
+
1507
+ .run-button::after {
1508
+ content: '';
1509
+ position: absolute;
1510
+ top: 50%;
1511
+ left: -100%;
1512
+ width: 70%;
1513
+ height: 100%;
1514
+ background: linear-gradient(90deg,
1515
+ transparent,
1516
+ rgba(255, 255, 255, 0.2),
1517
+ transparent);
1518
+ transform: skewX(-25deg) translateY(-50%);
1519
+ animation: buttonShine 4s infinite;
1520
+ }
1521
+
1522
+ .run-button:hover {
1523
+ background: linear-gradient(135deg, rgba(0, 255, 157, 1), rgba(0, 180, 100, 1));
1524
+ transform: translateY(-2px) scale(1.03);
1525
+ box-shadow: 0 0 25px rgba(0, 255, 157, 0.5), 0 0 5px rgba(0, 238, 255, 0.3);
1526
+ letter-spacing: 1.5px;
1527
+ }
1528
+
1529
+ @keyframes buttonGlow {
1530
+ 0% {
1531
+ background-position: 0% 0;
1532
+ }
1533
+ 100% {
1534
+ background-position: 300% 0;
1535
+ }
1536
+ }
1537
+
1538
+ @keyframes buttonShine {
1539
+ 0% {
1540
+ left: -100%;
1541
+ }
1542
+ 20%, 100% {
1543
+ left: 200%;
1544
+ }
1545
+ }
1546
+
1547
+
1548
+ .image-modal {
1549
+ display: none;
1550
+ position: fixed;
1551
+ top: 0;
1552
+ left: 0;
1553
+ width: 100%;
1554
+ height: 100%;
1555
+ background-color: rgba(0, 0, 0, 0.8);
1556
+ z-index: 1000;
1557
+ justify-content: center;
1558
+ align-items: center;
1559
+ }
1560
+
1561
+ .image-modal.active {
1562
+ display: flex;
1563
+ }
1564
+
1565
+ .modal-content {
1566
+ max-width: 90%;
1567
+ max-height: 90%;
1568
+ }
1569
+
1570
+ .close-modal {
1571
+ position: absolute;
1572
+ top: 20px;
1573
+ right: 30px;
1574
+ color: white;
1575
+ font-size: 30px;
1576
+ cursor: pointer;
1577
+ }
1578
+
1579
+
1580
+ .python-modal {
1581
+ display: none;
1582
+ position: fixed;
1583
+ top: 0;
1584
+ left: 0;
1585
+ width: 100%;
1586
+ height: 100%;
1587
+ background-color: rgba(0, 0, 0, 0.8);
1588
+ z-index: 1000;
1589
+ justify-content: center;
1590
+ align-items: center;
1591
+ }
1592
+
1593
+ .python-modal.active {
1594
+ display: flex;
1595
+ }
1596
+
1597
+ .python-console {
1598
+ width: 80%;
1599
+ height: 80%;
1600
+ background-color: #1e1e1e;
1601
+ color: #f8f8f8;
1602
+ border-radius: 8px;
1603
+ padding: 15px;
1604
+ font-family: 'Courier New', monospace;
1605
+ overflow: auto;
1606
+ }
1607
+
1608
+ .python-output {
1609
+ white-space: pre-wrap;
1610
+ line-height: 1.5;
1611
+ }
1612
+
1613
+ .step-line {
1614
+ flex-grow: 1;
1615
+ height: 2px;
1616
+ background: linear-gradient(90deg, rgba(0, 238, 255, 0.8), rgba(255, 42, 109, 0.8));
1617
+ margin-left: 10px;
1618
+ box-shadow: 0 0 8px rgba(0, 238, 255, 0.3);
1619
+ }
1620
+
1621
+ .step-info {
1622
+ margin-left: 15px;
1623
+ font-weight: bold;
1624
+ color: var(--text-light);
1625
+ font-size: 0.9em;
1626
+ }
1627
+
1628
+ .step-item strong {
1629
+ display: block;
1630
+ margin-bottom: 8px;
1631
+ color: #007bff;
1632
+ font-size: 0.9em;
1633
+ }
1634
+
1635
+ .step-item div {
1636
+ color: #444;
1637
+ line-height: 1.6;
1638
+ }
1639
+
1640
+ .title {
1641
+ font-size: 7rem;
1642
+ margin-bottom: 1rem;
1643
+ background: linear-gradient(45deg, #00dc82 0%, #36e4da 50%, #0047e1 100%);
1644
+ -webkit-background-clip: text;
1645
+ -webkit-text-fill-color: transparent;
1646
+ animation: glow 2s ease-in-out infinite alternate;
1647
+ letter-spacing: -2px;
1648
+ font-weight: 900;
1649
+ line-height: 1;
1650
+ }
1651
+
1652
+ @keyframes glow {
1653
+ from {
1654
+ text-shadow: 0 0 20px rgba(0, 220, 130, 0.6),
1655
+ 0 0 40px rgba(54, 228, 218, 0.4),
1656
+ 0 0 60px rgba(0, 71, 225, 0.2);
1657
+ }
1658
+ to {
1659
+ text-shadow: 0 0 40px rgba(0, 220, 130, 0.8),
1660
+ 0 0 60px rgba(54, 228, 218, 0.6),
1661
+ 0 0 80px rgba(0, 71, 225, 0.4);
1662
+ }
1663
+ }
1664
+
1665
+ .subtitle {
1666
+ font-size: 1.8rem;
1667
+ margin-bottom: 1.5rem;
1668
+ color: #999;
1669
+ font-weight: 500;
1670
+ letter-spacing: 0.5px;
1671
+ line-height: 1.3;
1672
+ }
1673
+
1674
+ .description {
1675
+ font-size: 1.1rem;
1676
+ line-height: 1.6;
1677
+ margin-bottom: 2.5rem;
1678
+ color: #888;
1679
+ max-width: 680px;
1680
+ margin-left: auto;
1681
+ margin-right: auto;
1682
+ font-weight: 400;
1683
+ letter-spacing: 0.2px;
1684
+ }
1685
+
1686
+ .cta-button {
1687
+ display: inline-block;
1688
+ padding: 0.9rem 2.5rem;
1689
+ font-size: 1rem;
1690
+ color: white;
1691
+ background: linear-gradient(45deg, #00dc82, #36e4da);
1692
+ border: none;
1693
+ border-radius: 25px;
1694
+ cursor: pointer;
1695
+ text-decoration: none;
1696
+ transition: all 0.3s ease;
1697
+ font-weight: 600;
1698
+ letter-spacing: 2px;
1699
+ text-transform: uppercase;
1700
+ }
1701
+
1702
+ .cta-button:hover {
1703
+ transform: translateY(-2px) scale(1.03);
1704
+ box-shadow: 0 6px 15px rgba(0, 220, 130, 0.4);
1705
+ }
1706
+
1707
+
1708
+ @media screen and (max-width: 1200px) {
1709
+ .title {
1710
+ font-size: 6rem;
1711
+ }
1712
+
1713
+ .hero-section {
1714
+ padding: 2rem 1.5rem;
1715
+ max-width: 800px;
1716
+ }
1717
+ }
1718
+
1719
+
1720
+
1721
+
1722
+
1723
+ @media screen and (max-width: 360px) {
1724
+ .title {
1725
+ font-size: 3rem;
1726
+ }
1727
+
1728
+ .subtitle {
1729
+ font-size: 1.1rem;
1730
+ }
1731
+
1732
+ .description {
1733
+ font-size: 0.85rem;
1734
+ }
1735
+
1736
+ .cta-button {
1737
+ padding: 0.6rem 1.8rem;
1738
+ font-size: 0.85rem;
1739
+ }
1740
+ }
1741
+
1742
+
1743
+ @media screen and (max-height: 700px) {
1744
+ .hero-section {
1745
+ padding: 1rem;
1746
+ }
1747
+
1748
+ .description {
1749
+ margin-bottom: 2rem;
1750
+ }
1751
+ }
1752
+
1753
+
1754
+ @media screen and (max-height: 500px) and (orientation: landscape) {
1755
+ .hero-section {
1756
+ padding: 1rem;
1757
+ }
1758
+
1759
+ .title {
1760
+ font-size: 3.5rem;
1761
+ margin-bottom: 0.5rem;
1762
+ }
1763
+
1764
+ .subtitle {
1765
+ font-size: 1.2rem;
1766
+ margin-bottom: 0.8rem;
1767
+ }
1768
+
1769
+ .description {
1770
+ font-size: 0.9rem;
1771
+ margin-bottom: 1.5rem;
1772
+ }
1773
+
1774
+ .cta-button {
1775
+ padding: 0.8rem 2.5rem;
1776
+ }
1777
+
1778
+ .emoji {
1779
+ display: none;
1780
+ }
1781
+ }
1782
+
1783
+
1784
+ .home-container {
1785
+ min-height: 100vh;
1786
+ display: flex;
1787
+ justify-content: center;
1788
+ align-items: center;
1789
+ background-color: #000000;
1790
+ color: white;
1791
+ position: relative;
1792
+ overflow: hidden;
1793
+ }
1794
+
1795
+ .home-container::before {
1796
+ display: none;
1797
+ }
1798
+
1799
+ .hero-section {
1800
+ text-align: center;
1801
+ padding: 2rem;
1802
+ position: relative;
1803
+ z-index: 1;
1804
+ max-width: 1000px;
1805
+ margin: 0 auto;
1806
+ background: transparent;
1807
+ border: none;
1808
+ box-shadow: none;
1809
+ }
1810
+
1811
+ .floating-emojis {
1812
+ position: absolute;
1813
+ top: 0;
1814
+ left: 0;
1815
+ width: 100%;
1816
+ height: 100%;
1817
+ pointer-events: none;
1818
+ }
1819
+
1820
+ .emoji {
1821
+ position: absolute;
1822
+ font-size: 2.5rem;
1823
+ opacity: 0;
1824
+ animation: float 10s ease-in-out infinite;
1825
+ animation-delay: var(--delay);
1826
+ filter: drop-shadow(0 0 10px rgba(0, 220, 130, 0.3));
1827
+ }
1828
+
1829
+ .emoji:nth-child(1) { top: 20%; left: 20%; }
1830
+ .emoji:nth-child(2) { top: 30%; left: 80%; }
1831
+ .emoji:nth-child(3) { top: 70%; left: 30%; }
1832
+ .emoji:nth-child(4) { top: 60%; left: 70%; }
1833
+ .emoji:nth-child(5) { top: 40%; left: 50%; }
1834
+
1835
+ @keyframes float {
1836
+ 0% {
1837
+ transform: translateY(0) rotate(0);
1838
+ opacity: 0;
1839
+ }
1840
+ 20% {
1841
+ opacity: 1;
1842
+ }
1843
+ 80% {
1844
+ opacity: 1;
1845
+ }
1846
+ 100% {
1847
+ transform: translateY(-100vh) rotate(360deg);
1848
+ opacity: 0;
1849
+ }
1850
+ }
1851
+
1852
+ .step-info-container {
1853
+ width: 100%;
1854
+ padding: 5px;
1855
+ margin-bottom: 10px;
1856
+ box-sizing: border-box;
1857
+ }
1858
+
1859
+ .step-info-box {
1860
+ padding: 10px;
1861
+ background-color: rgba(0, 20, 40, 0.3);
1862
+ border: 1px solid rgba(0, 238, 255, 0.1);
1863
+ border-radius: 5px;
1864
+ display: flex;
1865
+ align-items: center;
1866
+ gap: 10px;
1867
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.1);
1868
+ position: relative;
1869
+ overflow: hidden;
1870
+ box-sizing: border-box;
1871
+ width: 100%;
1872
+ }
1873
+
1874
+ .current-step {
1875
+ background-color: #f0f5ff;
1876
+ border: 1px solid #e0e0e0;
1877
+ border-left: 3px solid #4285f4;
1878
+ padding: 8px 12px;
1879
+ margin-top: 8px;
1880
+ border-radius: 4px;
1881
+ display: flex;
1882
+ align-items: center;
1883
+ }
1884
+
1885
+ .emoji-icon {
1886
+ margin-right: 14px;
1887
+ font-size: 18px;
1888
+ display: inline-flex;
1889
+ width: 36px;
1890
+ height: 36px;
1891
+ justify-content: center;
1892
+ align-items: center;
1893
+ background: linear-gradient(135deg, rgba(45, 49, 66, 0.8), rgba(28, 31, 40, 0.8));
1894
+ border-radius: 50%;
1895
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2), inset 0 0 15px rgba(60, 80, 220, 0.3);
1896
+ position: relative;
1897
+ z-index: 2;
1898
+ border: 1px solid rgba(60, 80, 220, 0.15);
1899
+ color: rgba(255, 255, 255, 0.9);
1900
+ }
1901
+
1902
+ .emoji-icon::before {
1903
+ content: '';
1904
+ position: absolute;
1905
+ width: 100%;
1906
+ height: 100%;
1907
+ border-radius: 50%;
1908
+ background: radial-gradient(circle at 30% 30%, rgba(60, 80, 220, 0.25), transparent 60%);
1909
+ z-index: -1;
1910
+ }
1911
+
1912
+ .step-highlight {
1913
+ background-color: #ffefef;
1914
+ border: 1px solid #ffcdd2;
1915
+ border-left: 3px solid #f44336;
1916
+ padding: 8px 12px;
1917
+ margin-top: 8px;
1918
+ border-radius: 4px;
1919
+ display: flex;
1920
+ align-items: center;
1921
+ }
1922
+
1923
+ .content-highlight {
1924
+ background-color: #e3f2fd;
1925
+ border: 1px solid #bbdefb;
1926
+ border-left: 3px solid #2196f3;
1927
+ padding: 10px;
1928
+ margin-bottom: 10px;
1929
+ border-radius: 4px;
1930
+ overflow-x: auto;
1931
+ }
1932
+
1933
+ .content-highlight pre {
1934
+ margin: 0;
1935
+ white-space: pre-wrap;
1936
+ word-break: break-word;
1937
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
1938
+ font-size: 14px;
1939
+ line-height: 1.5;
1940
+ }
1941
+
1942
+
1943
+ .header {
1944
+ position: fixed;
1945
+ top: 0;
1946
+ left: 0;
1947
+ right: 0;
1948
+ height: 56px;
1949
+ background-color: rgba(10, 10, 26, 0.9);
1950
+ backdrop-filter: blur(10px);
1951
+ border-bottom: 1px solid var(--border-color);
1952
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
1953
+ display: flex;
1954
+ align-items: center;
1955
+ justify-content: space-between;
1956
+ padding: 0 20px;
1957
+ z-index: 100;
1958
+ transition: all 0.3s ease;
1959
+ }
1960
+
1961
+ .header-left, .header-center, .header-right {
1962
+ display: flex;
1963
+ align-items: center;
1964
+ gap: 16px;
1965
+ }
1966
+
1967
+ .header-left {
1968
+ flex: 1;
1969
+ }
1970
+
1971
+ .logo {
1972
+ display: flex;
1973
+ align-items: center;
1974
+ gap: 10px;
1975
+ }
1976
+
1977
+ .logo-img {
1978
+ display: none;
1979
+ }
1980
+
1981
+ .logo-text {
1982
+ font-weight: 700;
1983
+ font-size: 18px;
1984
+ background: linear-gradient(90deg, var(--primary-color), var(--error-color));
1985
+ -webkit-background-clip: text;
1986
+ background-clip: text;
1987
+ -webkit-text-fill-color: transparent;
1988
+ margin-left: 0;
1989
+ letter-spacing: 1px;
1990
+ text-shadow: none;
1991
+ text-transform: uppercase;
1992
+ text-decoration: none;
1993
+ }
1994
+
1995
+
1996
+ .history-toggle {
1997
+ all: unset;
1998
+ cursor: pointer;
1999
+ color: var(--primary-color);
2000
+ position: relative;
2001
+ margin: 0 15px 0 0;
2002
+ padding: 0;
2003
+ font-size: inherit;
2004
+ line-height: normal;
2005
+ display: inline-block;
2006
+ }
2007
+
2008
+ .history-toggle i {
2009
+ font-size: 18px;
2010
+ text-shadow: 0 0 5px rgba(0, 238, 255, 0.5);
2011
+ }
2012
+
2013
+
2014
+ .history-count {
2015
+ position: absolute;
2016
+ top: -5px;
2017
+ right: -5px;
2018
+ background-color: #555;
2019
+ color: white;
2020
+ min-width: 14px;
2021
+ height: 14px;
2022
+ border-radius: 7px;
2023
+ font-size: 9px;
2024
+ font-weight: 600;
2025
+ text-align: center;
2026
+ line-height: 14px;
2027
+ padding: 0 3px;
2028
+ }
2029
+
2030
+
2031
+ .history-panel {
2032
+ position: fixed;
2033
+ left: 0;
2034
+ top: 56px;
2035
+ width: 280px;
2036
+ height: calc(100vh - 56px);
2037
+ background-color: white;
2038
+ box-shadow: 3px 0 10px rgba(0, 0, 0, 0.05);
2039
+ z-index: 99;
2040
+ transform: translateX(-100%);
2041
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
2042
+ overflow: hidden;
2043
+ display: flex;
2044
+ flex-direction: column;
2045
+ }
2046
+
2047
+ .history-panel.show {
2048
+ transform: translateX(0);
2049
+ }
2050
+
2051
+ .history-header {
2052
+ display: flex;
2053
+ align-items: center;
2054
+ justify-content: space-between;
2055
+ padding: 15px 20px;
2056
+ border-bottom: 1px solid #eee;
2057
+ }
2058
+
2059
+ .history-title {
2060
+ font-size: 16px;
2061
+ font-weight: 600;
2062
+ color: var(--primary-color);
2063
+ text-transform: uppercase;
2064
+ letter-spacing: 1px;
2065
+ text-shadow: 0 0 5px rgba(0, 238, 255, 0.3);
2066
+ }
2067
+
2068
+ .history-actions {
2069
+ display: flex;
2070
+ gap: 10px;
2071
+ }
2072
+
2073
+ .history-action-btn {
2074
+ background: transparent;
2075
+ border: none;
2076
+ color: #666;
2077
+ cursor: pointer;
2078
+ padding: 5px;
2079
+ border-radius: 4px;
2080
+ transition: all 0.2s;
2081
+ }
2082
+
2083
+ .history-action-btn:hover {
2084
+ background-color: rgba(0, 0, 0, 0.05);
2085
+ color: #0575E6;
2086
+ transform: none;
2087
+ box-shadow: none;
2088
+ }
2089
+
2090
+ .task-list {
2091
+ flex: 1;
2092
+ overflow-y: auto;
2093
+ padding: 10px 15px;
2094
+ }
2095
+
2096
+ .task-card {
2097
+ background: #fff;
2098
+ padding: 12px 15px;
2099
+ margin-bottom: 10px;
2100
+ border-radius: 8px;
2101
+ cursor: pointer;
2102
+ border: 1px solid #eee;
2103
+ transition: all 0.2s;
2104
+ }
2105
+
2106
+ .task-card:hover {
2107
+ transform: translateY(-2px);
2108
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
2109
+ border-color: #ddd;
2110
+ }
2111
+
2112
+ .task-card.active {
2113
+ border-left: 3px solid #0e68f1;
2114
+ background-color: rgba(14, 104, 241, 0.05);
2115
+ }
2116
+
2117
+ .task-title {
2118
+ font-weight: 500;
2119
+ margin-bottom: 5px;
2120
+ color: #333;
2121
+ overflow: hidden;
2122
+ text-overflow: ellipsis;
2123
+ white-space: nowrap;
2124
+ }
2125
+
2126
+ .task-meta {
2127
+ display: flex;
2128
+ justify-content: space-between;
2129
+ font-size: 12px;
2130
+ color: #888;
2131
+ }
2132
+
2133
+
2134
+ .overlay {
2135
+ position: fixed;
2136
+ top: 0;
2137
+ left: 0;
2138
+ width: 100vw;
2139
+ height: 100vh;
2140
+ background-color: rgba(0, 0, 0, 0.3);
2141
+ z-index: 98;
2142
+ opacity: 0;
2143
+ pointer-events: none;
2144
+ transition: opacity 0.3s ease;
2145
+ }
2146
+
2147
+ .overlay.show {
2148
+ opacity: 1;
2149
+ pointer-events: all;
2150
+ }
2151
+
2152
+
2153
+ .container.with-history {
2154
+ padding-left: 280px;
2155
+ transition: padding 0.3s cubic-bezier(0.4, 0, 0.2, 1);
2156
+ }
2157
+
2158
+
2159
+ .welcome-title {
2160
+ font-size: 3.8rem;
2161
+ margin-bottom: 18px;
2162
+ color: #333;
2163
+ font-weight: 700;
2164
+ line-height: 1.2;
2165
+ letter-spacing: -0.5px;
2166
+ }
2167
+
2168
+
2169
+ .welcome-message p {
2170
+ font-size: 1.1rem;
2171
+ color: #555;
2172
+ margin-bottom: 10px;
2173
+ background: linear-gradient(135deg, #0575E6 0%, #0096FF 35%, #00B4FF 65%, #00D2FF 100%);
2174
+ -webkit-background-clip: text;
2175
+ background-clip: text;
2176
+ -webkit-text-fill-color: transparent;
2177
+ font-weight: 600;
2178
+ animation: fadeIn 0.8s ease-in-out;
2179
+ animation-delay: 0.2s;
2180
+ animation-fill-mode: both;
2181
+ }
2182
+
2183
+
2184
+ .login-btn i {
2185
+ font-size: 14px;
2186
+ }
2187
+
2188
+
2189
+ button {
2190
+ border: none;
2191
+ cursor: pointer;
2192
+ transition: all 0.3s ease;
2193
+ }
2194
+
2195
+
2196
+ .input-container {
2197
+ width: 100%;
2198
+ background-color: #000000;
2199
+ border-radius: 8px;
2200
+ padding: 15px 20px;
2201
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
2202
+ display: flex;
2203
+ gap: 15px;
2204
+ margin-top: auto;
2205
+ border: 2px solid transparent !important;
2206
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.3) !important;
2207
+ position: relative;
2208
+ z-index: 10;
2209
+ overflow: hidden;
2210
+ }
2211
+
2212
+
2213
+ #prompt-input {
2214
+ flex: 1;
2215
+ padding: 14px 20px;
2216
+ border: 1px solid var(--border-color);
2217
+ border-radius: 4px;
2218
+ font-size: 1rem;
2219
+ transition: all 0.3s ease;
2220
+ background-color: rgba(10, 10, 26, 0.7);
2221
+ color: var(--text-color);
2222
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.2);
2223
+ }
2224
+
2225
+ #prompt-input:focus {
2226
+ animation: inputGlow 3s infinite alternate;
2227
+ border-color: var(--primary-color);
2228
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.4),
2229
+ 0 0 10px rgba(255, 42, 109, 0.2);
2230
+ }
2231
+
2232
+ #prompt-input::placeholder {
2233
+ color: rgba(255, 255, 255, 0.4);
2234
+ }
2235
+
2236
+
2237
+ .title-text {
2238
+ position: relative;
2239
+ font-size: clamp(2.5rem, 8vw, 4rem);
2240
+ margin: 0.5em 0;
2241
+ color: transparent;
2242
+ letter-spacing: 0.1em;
2243
+ font-weight: 700;
2244
+ line-height: 1;
2245
+ text-transform: uppercase;
2246
+ white-space: nowrap;
2247
+ background: linear-gradient(90deg, #fff, #fff 50%, #ff2a6d 50%, #ff2a6d);
2248
+ -webkit-background-clip: text;
2249
+ background-clip: text;
2250
+ filter: drop-shadow(0 0 0.4em rgba(0, 238, 255, 0.3));
2251
+ animation: titleShadow 3s infinite;
2252
+ width: 100%;
2253
+ display: inline-block;
2254
+ }
2255
+
2256
+
2257
+
2258
+
2259
+ .title-text::before {
2260
+ content: attr(data-text);
2261
+ position: absolute;
2262
+ top: 0;
2263
+ left: -2px;
2264
+ width: 100%;
2265
+ height: 100%;
2266
+ background: linear-gradient(90deg, #fff, #fff 50%, #ff2a6d 50%, #ff2a6d);
2267
+ -webkit-background-clip: text;
2268
+ background-clip: text;
2269
+ -webkit-text-fill-color: transparent;
2270
+ mix-blend-mode: overlay;
2271
+ opacity: 0.3;
2272
+ z-index: -1;
2273
+ animation: glitchMove 3s infinite;
2274
+ }
2275
+
2276
+ .title-text::after {
2277
+ content: attr(data-text);
2278
+ position: absolute;
2279
+ top: 0;
2280
+ left: 2px;
2281
+ width: 100%;
2282
+ height: 100%;
2283
+ background: linear-gradient(90deg, #fff, #fff 50%, #ff2a6d 50%, #ff2a6d);
2284
+ -webkit-background-clip: text;
2285
+ background-clip: text;
2286
+ -webkit-text-fill-color: transparent;
2287
+ mix-blend-mode: overlay;
2288
+ opacity: 0.3;
2289
+ z-index: -2;
2290
+ animation: glitchMove 2s infinite reverse;
2291
+ }
2292
+
2293
+
2294
+ @keyframes glitchMove {
2295
+ 0%, 100% {
2296
+ transform: translate(0);
2297
+ }
2298
+ 25% {
2299
+ transform: translate(-0.1em, 0.05em);
2300
+ }
2301
+ 50% {
2302
+ transform: translate(0.05em, -0.05em);
2303
+ }
2304
+ 75% {
2305
+ transform: translate(0.05em, 0.05em);
2306
+ }
2307
+ }
2308
+
2309
+
2310
+ @keyframes textBlink {
2311
+ 0%, 100% {
2312
+ opacity: 0;
2313
+ }
2314
+ 50% {
2315
+ opacity: 0.03;
2316
+ background: rgba(0, 238, 255, 0.1);
2317
+ }
2318
+ }
2319
+
2320
+
2321
+ .arrow-icon {
2322
+ display: inline-block;
2323
+ margin-left: 8px;
2324
+ font-weight: 700;
2325
+ animation: pulse-arrow 1.5s infinite ease-in-out;
2326
+ }
2327
+
2328
+ @keyframes pulse-arrow {
2329
+ 0% {
2330
+ transform: translateX(0);
2331
+ }
2332
+ 50% {
2333
+ transform: translateX(0.3em);
2334
+ }
2335
+ 100% {
2336
+ transform: translateX(0);
2337
+ }
2338
+ }
2339
+
2340
+
2341
+ .cyber-panel {
2342
+ position: relative;
2343
+ border: 1px solid rgba(0, 238, 255, 0.2) !important;
2344
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.2) !important;
2345
+ overflow: hidden;
2346
+ background-color: #000000 !important;
2347
+ }
2348
+
2349
+ .cyber-panel::before {
2350
+ content: none;
2351
+ }
2352
+
2353
+
2354
+ .history-title {
2355
+ font-size: 16px;
2356
+ font-weight: 600;
2357
+ color: var(--primary-color);
2358
+ text-transform: uppercase;
2359
+ letter-spacing: 1px;
2360
+ text-shadow: 0 0 5px rgba(0, 238, 255, 0.3);
2361
+ }
2362
+
2363
+
2364
+ @keyframes borderPulse {
2365
+ 0% {
2366
+ border-color: rgba(0, 238, 255, 0.3);
2367
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
2368
+ }
2369
+ 50% {
2370
+ border-color: rgba(255, 42, 109, 0.3);
2371
+ box-shadow: 0 0 20px rgba(255, 42, 109, 0.2);
2372
+ }
2373
+ 100% {
2374
+ border-color: rgba(0, 238, 255, 0.3);
2375
+ box-shadow: 0 0 15px rgba(0, 238, 255, 0.2);
2376
+ }
2377
+ }
2378
+
2379
+
2380
+ .cyber-panel, .result-panel, .input-container {
2381
+ animation: borderPulse 4s infinite ease-in-out;
2382
+ }
2383
+
2384
+
2385
+ .logo {
2386
+ position: relative;
2387
+ overflow: hidden;
2388
+ }
2389
+
2390
+ .logo::after {
2391
+ content: '';
2392
+ position: absolute;
2393
+ top: 0;
2394
+ left: -100%;
2395
+ width: 50%;
2396
+ height: 100%;
2397
+ background: linear-gradient(
2398
+ 90deg,
2399
+ transparent,
2400
+ rgba(0, 238, 255, 0.2),
2401
+ transparent
2402
+ );
2403
+ transform: skewX(-25deg);
2404
+ animation: shine 3s infinite;
2405
+ }
2406
+
2407
+ @keyframes shine {
2408
+ 0% {
2409
+ left: -100%;
2410
+ }
2411
+ 20% {
2412
+ left: 100%;
2413
+ }
2414
+ 100% {
2415
+ left: 100%;
2416
+ }
2417
+
2418
+ }
2419
+
2420
+
2421
+ #prompt-input {
2422
+ position: relative;
2423
+ background-color: rgba(10, 10, 26, 0.8);
2424
+ color: var(--text-color);
2425
+ caret-color: var(--primary-color);
2426
+ }
2427
+
2428
+ #prompt-input:focus {
2429
+ animation: borderPulse 4s infinite ease-in-out;
2430
+ }
2431
+
2432
+
2433
+ .send-btn:hover, .login-btn:hover, .cta-button:hover {
2434
+ background: linear-gradient(135deg, rgba(0, 238, 255, 1), rgba(0, 71, 225, 1));
2435
+ transform: translateY(-2px) scale(1.03);
2436
+ box-shadow: 0 0 25px rgba(0, 238, 255, 0.5), 0 0 5px rgba(255, 42, 109, 0.3);
2437
+ letter-spacing: 1.5px;
2438
+ }
2439
+
2440
+
2441
+ .welcome-message {
2442
+ position: relative;
2443
+ }
2444
+
2445
+ .welcome-message::before {
2446
+ display: none;
2447
+ }
2448
+
2449
+ .welcome-message::after {
2450
+ display: none;
2451
+ }
2452
+
2453
+
2454
+ .step-item:hover .log-header {
2455
+ background-color: rgba(0, 238, 255, 0.05);
2456
+ }
2457
+
2458
+
2459
+ .status-text {
2460
+ font-family: 'Courier New', monospace;
2461
+ color: var(--primary-color) !important;
2462
+ }
2463
+
2464
+ .status-text::after {
2465
+ content: '|';
2466
+ color: var(--primary-color);
2467
+ }
2468
+
2469
+
2470
+ ::selection {
2471
+ background: rgba(0, 238, 255, 0.2);
2472
+ color: var(--primary-color);
2473
+ }
2474
+
2475
+
2476
+ .history-panel {
2477
+ background: linear-gradient(180deg,
2478
+ rgba(22, 24, 36, 0.95),
2479
+ rgba(15, 15, 30, 0.95)
2480
+ );
2481
+ }
2482
+
2483
+
2484
+ @keyframes pulse-light {
2485
+ 0% {
2486
+ opacity: 0.5;
2487
+ box-shadow: 0 0 0.3em var(--primary-color);
2488
+ }
2489
+ 50% {
2490
+ opacity: 1;
2491
+ box-shadow: 0 0 0.8em var(--primary-color), 0 0 0.3em var(--error-color);
2492
+ }
2493
+ 100% {
2494
+ opacity: 0.5;
2495
+ box-shadow: 0 0 0.3em var(--primary-color);
2496
+ }
2497
+
2498
+ }
2499
+
2500
+
2501
+ .logo-text-large {
2502
+ font-size: 2.8rem;
2503
+ color: #fff;
2504
+ text-shadow: 0 0 20px rgba(0, 238, 255, 0.8);
2505
+ margin: 5px 0;
2506
+ font-weight: 500;
2507
+ }
2508
+
2509
+ .subtitle-text {
2510
+ font-size: 1.4rem;
2511
+ letter-spacing: 4px;
2512
+ color: #00eeff;
2513
+ margin: 20px 0 20px;
2514
+ font-weight: 500;
2515
+ text-shadow: 0 0 15px rgba(0, 238, 255, 0.8);
2516
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
2517
+ animation: pulse-light 2s infinite;
2518
+ }
2519
+
2520
+ .command-text {
2521
+ font-size: 0.8rem;
2522
+ letter-spacing: 2px;
2523
+ color: rgba(255, 255, 255, 0.9);
2524
+ margin: 15px 0;
2525
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
2526
+ position: relative;
2527
+ padding: 15px 0;
2528
+ text-transform: uppercase;
2529
+ animation: fadeIn 1.5s ease-in-out;
2530
+ }
2531
+
2532
+ .command-text::before, .command-text::after {
2533
+ content: '';
2534
+ position: absolute;
2535
+ width: 0;
2536
+ height: 2px;
2537
+ background: linear-gradient(90deg,
2538
+ transparent,
2539
+ rgba(0, 238, 255, 0.8),
2540
+ rgba(255, 42, 109, 0.8),
2541
+ rgba(0, 238, 255, 0.8),
2542
+ transparent);
2543
+ animation: lineExpand 2.5s forwards;
2544
+ background-size: 200% 100%;
2545
+ }
2546
+
2547
+ .command-text::before {
2548
+ top: 0;
2549
+ left: 50%;
2550
+ transform: translateX(-50%);
2551
+ }
2552
+
2553
+ .command-text::after {
2554
+ bottom: 0;
2555
+ left: 50%;
2556
+ transform: translateX(-50%);
2557
+ }
2558
+
2559
+ @keyframes lineExpand {
2560
+ 0% { width: 0; }
2561
+ 100% { width: 80%; }
2562
+ }
2563
+
2564
+ .dash {
2565
+ color: #00eeff;
2566
+ animation: blinkDash 1.5s infinite;
2567
+ }
2568
+
2569
+ @keyframes blinkDash {
2570
+ 0%, 100% { opacity: 1; }
2571
+ 50% { opacity: 0.3; }
2572
+ }
2573
+
2574
+
2575
+ @keyframes borderFlow {
2576
+ 0% {
2577
+ background-position: 0% 0;
2578
+ }
2579
+ 100% {
2580
+ background-position: 400% 0;
2581
+ }
2582
+ }
2583
+
2584
+
2585
+ @keyframes innerGlow {
2586
+ 0% {
2587
+ box-shadow: inset 0 0 30px rgba(0, 238, 255, 0.3),
2588
+ inset 0 0 15px rgba(255, 42, 109, 0.2);
2589
+ }
2590
+ 100% {
2591
+ box-shadow: inset 0 0 50px rgba(0, 238, 255, 0.5),
2592
+ inset 0 0 25px rgba(255, 42, 109, 0.3);
2593
+ }
2594
+ }
2595
+
2596
+
2597
+ #prompt-input {
2598
+ border: 2px solid var(--border-color);
2599
+ background-color: rgba(10, 10, 26, 0.7);
2600
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.2);
2601
+ }
2602
+
2603
+ #prompt-input:focus {
2604
+ animation: inputGlow 3s infinite alternate;
2605
+ border-color: var(--primary-color);
2606
+ box-shadow: 0 0 20px rgba(0, 238, 255, 0.4),
2607
+ 0 0 10px rgba(255, 42, 109, 0.2);
2608
+ }
2609
+
2610
+ @keyframes inputGlow {
2611
+ 0% {
2612
+ border-color: var(--primary-color);
2613
+ box-shadow: 0 0 0.8em rgba(0, 238, 255, 0.4);
2614
+ }
2615
+ 100% {
2616
+ border-color: var(--error-color);
2617
+ box-shadow: 0 0 1em rgba(255, 42, 109, 0.5);
2618
+ }
2619
+ }
2620
+
2621
+
2622
+ @keyframes logoFloat {
2623
+ 0%, 100% {
2624
+ transform: translateY(0);
2625
+ filter: drop-shadow(0 0 0.8em rgba(0, 238, 255, 0.7));
2626
+ }
2627
+ 50% {
2628
+ transform: translateY(-0.6em);
2629
+ filter: drop-shadow(0 0 1.3em rgba(0, 238, 255, 0.9))
2630
+ drop-shadow(0 0 0.6em rgba(255, 42, 109, 0.5));
2631
+ }
2632
+ }
2633
+
2634
+
2635
+ .subtitle-text {
2636
+ text-shadow: 0 0 15px rgba(0, 238, 255, 0.8);
2637
+ animation: subtitlePulse 3s infinite;
2638
+ letter-spacing: 5px;
2639
+ }
2640
+
2641
+ @keyframes subtitlePulse {
2642
+ 0%, 100% {
2643
+ opacity: 0.9;
2644
+ text-shadow: 0 0 15px rgba(0, 238, 255, 0.7);
2645
+ }
2646
+ 50% {
2647
+ opacity: 1;
2648
+ text-shadow: 0 0 25px rgba(0, 238, 255, 0.9),
2649
+ 0 0 10px rgba(255, 42, 109, 0.6);
2650
+ letter-spacing: 6px;
2651
+ }
2652
+ }
2653
+
2654
+
2655
+ .send-btn:hover {
2656
+ background: linear-gradient(135deg, rgba(0, 238, 255, 1), rgba(0, 71, 225, 1));
2657
+ transform: translateY(-2px) scale(1.03);
2658
+ box-shadow: 0 0 25px rgba(0, 238, 255, 0.5), 0 0 5px rgba(255, 42, 109, 0.3);
2659
+ letter-spacing: 1.5px;
2660
+ }
2661
+
2662
+ .send-btn:active {
2663
+ transform: translateY(0px);
2664
+ box-shadow: 0 2px 10px rgba(5, 117, 230, 0.15);
2665
+ }
2666
+
2667
+
2668
+ .input-container::before {
2669
+ content: '';
2670
+ position: absolute;
2671
+ top: -2px;
2672
+ left: -2px;
2673
+ right: -2px;
2674
+ bottom: -2px;
2675
+ z-index: -1;
2676
+ background: linear-gradient(90deg,
2677
+ var(--primary-color),
2678
+ var(--error-color),
2679
+ var(--success-color),
2680
+ var(--primary-color));
2681
+ background-size: 400% 100%;
2682
+ animation: borderFlow 8s linear infinite;
2683
+ border-radius: inherit;
2684
+ }
2685
+
2686
+ .input-container::after {
2687
+ content: '';
2688
+ position: absolute;
2689
+ top: 2px;
2690
+ left: 2px;
2691
+ right: 2px;
2692
+ bottom: 2px;
2693
+ background: var(--bg-color);
2694
+ border-radius: inherit;
2695
+ z-index: -1;
2696
+ box-shadow: inset 0 0 20px rgba(0, 238, 255, 0.2),
2697
+ inset 0 0 10px rgba(255, 42, 109, 0.1);
2698
+ pointer-events: none;
2699
+ }
2700
+
2701
+
2702
+ .result-panel::after {
2703
+ content: '';
2704
+ position: absolute;
2705
+ top: 2px;
2706
+ left: 2px;
2707
+ right: 2px;
2708
+ bottom: 2px;
2709
+ background: rgba(15, 15, 30, 0.95);
2710
+ border-radius: inherit;
2711
+ z-index: -1;
2712
+ box-shadow: inset 0 0 20px rgba(0, 238, 255, 0.2),
2713
+ inset 0 0 10px rgba(255, 42, 109, 0.1);
2714
+ pointer-events: none;
2715
+ }
2716
+
2717
+
2718
+ ::-webkit-scrollbar {
2719
+ width: 6px;
2720
+ height: 6px;
2721
+ background: transparent;
2722
+ }
2723
+
2724
+ ::-webkit-scrollbar-track {
2725
+ background: rgba(0, 0, 0, 0.1);
2726
+ border-radius: 3px;
2727
+ }
2728
+
2729
+ ::-webkit-scrollbar-thumb {
2730
+ background: rgba(0, 238, 255, 0.3);
2731
+ border-radius: 3px;
2732
+ transition: all 0.3s ease;
2733
+ }
2734
+
2735
+ ::-webkit-scrollbar-thumb:hover {
2736
+ background: rgba(0, 238, 255, 0.5);
2737
+ }
2738
+
2739
+ * {
2740
+ scrollbar-width: thin;
2741
+ scrollbar-color: rgba(0, 238, 255, 0.3) rgba(0, 0, 0, 0.1);
2742
+ }
2743
+
2744
+ * {
2745
+ -ms-overflow-style: auto;
2746
+ }
2747
+
2748
+ @media screen and (max-width: 1024px) {
2749
+ .container.with-result {
2750
+ width: 100%;
2751
+ margin-right: auto;
2752
+ margin-left: auto;
2753
+ }
2754
+
2755
+ .result-panel {
2756
+ width: 80%;
2757
+ min-width: 300px;
2758
+ height: 50vh;
2759
+ position: fixed;
2760
+ right: 10%;
2761
+ left: 10%;
2762
+ top: 25vh;
2763
+ margin: 0 auto;
2764
+ box-sizing: border-box;
2765
+ }
2766
+
2767
+ .result-panel.hidden {
2768
+ transform: translateY(calc(100% + 20px));
2769
+ display: none !important;
2770
+ }
2771
+
2772
+ .result-container {
2773
+ max-height: calc(50vh - 150px);
2774
+ }
2775
+ }
2776
+
2777
+ @media screen and (max-width: 480px) {
2778
+ .result-panel {
2779
+ width: 90%;
2780
+ right: 5%;
2781
+ left: 5%;
2782
+ box-sizing: border-box;
2783
+ }
2784
+
2785
+ .result-container {
2786
+ padding: 5px;
2787
+ }
2788
+ }
2789
+
2790
+
2791
+
2792
+
2793
+ .log-prefix time {
2794
+ font-weight: 500;
2795
+ color: var(--primary-color);
2796
+ padding: 0 5px;
2797
+ background-color: rgba(0, 238, 255, 0.1);
2798
+ border-radius: 3px;
2799
+ box-shadow: 0 0 5px rgba(0, 238, 255, 0.2);
2800
+ display: inline-block;
2801
+ }
2802
+
2803
+
2804
+ .log-prefix-icon {
2805
+ display: inline-flex;
2806
+ width: 26px;
2807
+ height: 26px;
2808
+ justify-content: center;
2809
+ align-items: center;
2810
+ background: rgba(0, 238, 255, 0.1);
2811
+ border-radius: 50%;
2812
+ margin-right: 6px;
2813
+ box-shadow: 0 0 10px rgba(0, 238, 255, 0.2);
2814
+ border: 1px solid var(--border-color);
2815
+ color: var(--primary-color);
2816
+ flex-shrink: 0;
2817
+ }
2818
+
2819
+
2820
+ .steps-container::-webkit-scrollbar,
2821
+ .result-container::-webkit-scrollbar {
2822
+ width: 8px;
2823
+ height: 8px;
2824
+ }
2825
+
2826
+ .steps-container::-webkit-scrollbar-track,
2827
+ .result-container::-webkit-scrollbar-track {
2828
+ background: rgba(0, 0, 0, 0.2);
2829
+ border-radius: 4px;
2830
+ }
2831
+
2832
+ .steps-container::-webkit-scrollbar-thumb,
2833
+ .result-container::-webkit-scrollbar-thumb {
2834
+ background: rgba(0, 238, 255, 0.4);
2835
+ border-radius: 4px;
2836
+ }
2837
+
2838
+ .steps-container::-webkit-scrollbar-thumb:hover,
2839
+ .result-container::-webkit-scrollbar-thumb:hover {
2840
+ background: rgba(0, 238, 255, 0.6);
2841
+ }
2842
+
2843
+ /* Adjust for horizontal scrollbar when needed */
2844
+ .result-container::-webkit-scrollbar-corner {
2845
+ background: rgba(0, 0, 0, 0.2);
2846
+ }
2847
+
2848
+
2849
+
2850
+
2851
+ .title-container {
2852
+ width: 100%;
2853
+ overflow: visible;
2854
+ text-align: center;
2855
+ margin: 0.5em auto;
2856
+ padding: 0;
2857
+ max-width: 100%;
2858
+ transform-origin: center;
2859
+ }
2860
+ .title-text {
2861
+ position: relative;
2862
+ font-size: clamp(1.8rem, 6vw, 3.2rem);
2863
+ margin: 0.5em auto;
2864
+ color: transparent;
2865
+ letter-spacing: 0em;
2866
+ font-weight: 700;
2867
+ line-height: 1;
2868
+ text-transform: uppercase;
2869
+ white-space: nowrap;
2870
+ background: linear-gradient(90deg, #fff, #fff 50%, #ff2a6d 50%, #ff2a6d);
2871
+ -webkit-background-clip: text;
2872
+ background-clip: text;
2873
+ filter: drop-shadow(0 0 0.4em rgba(0, 238, 255, 0.3));
2874
+ animation: titleShadow 3s infinite;
2875
+ width: auto;
2876
+ display: inline-block;
2877
+ padding: 0;
2878
+ transform: scale(0.9);
2879
+ max-width: 100%;
2880
+ }
static/themes/cyberpunk/templates/chat.html ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OpenManus - Cyberpunk</title>
7
+ <link rel="stylesheet" href="/static/themes/cyberpunk/static/style.css">
8
+ <!-- Add Font Awesome icon library -->
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ </head>
11
+ <body>
12
+ <!-- Top navigation bar -->
13
+ <header class="header">
14
+ <div class="header-left">
15
+ <a href="/" class="logo" style="text-decoration: none;">
16
+ <span class="logo-text">OPENMANUS</span>
17
+ </a>
18
+ </div>
19
+ <div class="header-right">
20
+ <!-- History icon button - using CSS class -->
21
+ <button class="history-toggle">
22
+ <i class="fas fa-history"></i>
23
+ <span class="history-count">0</span>
24
+ </button>
25
+ <a href="#" class="login-btn">
26
+ <i class="fas fa-user"></i>
27
+ LOGIN
28
+ </a>
29
+ </div>
30
+ </header>
31
+
32
+ <!-- History panel -->
33
+ <aside class="history-panel">
34
+ <div class="history-header">
35
+ <div class="history-title">History</div>
36
+ <div class="history-actions">
37
+ <button class="history-action-btn" title="Refresh" onclick="loadHistory()">
38
+ <i class="fas fa-sync-alt"></i>
39
+ </button>
40
+ </div>
41
+ </div>
42
+ <div id="task-list" class="task-list">
43
+ <!-- Task list will be dynamically loaded through JavaScript -->
44
+ </div>
45
+ </aside>
46
+
47
+ <!-- Background overlay -->
48
+ <div class="overlay"></div>
49
+
50
+ <!-- Main container -->
51
+ <div class="container">
52
+ <div class="main-panel">
53
+ <div id="task-container" class="task-container cyber-panel">
54
+ <div class="welcome-message">
55
+ <div class="logo-animation">
56
+ <img src="/static/themes/cyberpunk/static/logo_white.png" alt="OpenManus Logo" class="welcome-logo">
57
+ </div>
58
+
59
+ <div class="title-container">
60
+ <h2 class="title-text" data-text="MANUS INTERFACE">MANUS INTERFACE</h2>
61
+ </div>
62
+ <div class="title-glitch-overlay"></div>
63
+ <div class="subtitle-text">AUTONOMOUS INTELLIGENCE</div>
64
+ <div class="command-text"><span class="dash">—</span> / READY TO EXECUTE COMMAND \ <span class="dash">—</span></div>
65
+ </div>
66
+ <div id="steps-container" class="steps-container"></div>
67
+ </div>
68
+
69
+ <div id="result-panel" class="result-panel hidden">
70
+ <div class="result-header">
71
+ <h2>MANUS INTERFACE</h2>
72
+ <div class="result-controls">
73
+ <div class="minimize-result" onclick="toggleResultPanel()"></div>
74
+ </div>
75
+ </div>
76
+
77
+ <div class="step-info-container">
78
+ <div id="current-step" class="step-info-box">
79
+ <!-- Step information will be dynamically populated by JavaScript -->
80
+ </div>
81
+ </div>
82
+
83
+ <div id="result-container" class="result-container"></div>
84
+ </div>
85
+
86
+ <div class="input-container">
87
+ <input type="text" id="prompt-input" placeholder="输入指令...">
88
+ <button onclick="createTask()" class="send-btn">EXECUTE</button>
89
+ </div>
90
+ </div>
91
+ </div>
92
+
93
+ <script src="/static/themes/cyberpunk/static/main.js" defer></script>
94
+ </body>
95
+ </html>
static/themes/cyberpunk/theme.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "name": "赛博朋克",
3
+ "description": "具有霓虹灯和未来科技感的赛博朋克风格界面",
4
+ "author": "Ray",
5
+ "version": "1.0.0"
6
+ }
static/themes/openmanus/static/logo.png ADDED
static/themes/openmanus/static/main.js ADDED
@@ -0,0 +1,900 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let currentEventSource = null;
2
+ let historyVisible = false; // Track history panel status
3
+
4
+ function createTask() {
5
+ const promptInput = document.getElementById('prompt-input');
6
+ const prompt = promptInput.value.trim();
7
+
8
+ if (!prompt) {
9
+ alert("Please enter a valid task");
10
+ promptInput.focus();
11
+ return;
12
+ }
13
+
14
+ if (currentEventSource) {
15
+ currentEventSource.close();
16
+ currentEventSource = null;
17
+ }
18
+
19
+ const taskContainer = document.getElementById('task-container');
20
+ const stepsContainer = document.getElementById('steps-container');
21
+ const resultContainer = document.getElementById('result-container');
22
+
23
+ // Hide result panel
24
+ hideResultPanel();
25
+
26
+ // Hide welcome message, show step loading status
27
+ const welcomeMessage = taskContainer.querySelector('.welcome-message');
28
+ if (welcomeMessage) {
29
+ welcomeMessage.style.display = 'none';
30
+ }
31
+
32
+ stepsContainer.innerHTML = '<div class="loading">Initializing task...</div>';
33
+ resultContainer.innerHTML = '';
34
+
35
+ // Close history panel on mobile devices
36
+ closeHistoryOnMobile();
37
+
38
+ fetch('/tasks', {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json'
42
+ },
43
+ body: JSON.stringify({ prompt })
44
+ })
45
+ .then(response => {
46
+ if (!response.ok) {
47
+ return response.json().then(err => { throw new Error(err.detail || 'Request failed') });
48
+ }
49
+ return response.json();
50
+ })
51
+ .then(data => {
52
+ if (!data.task_id) {
53
+ throw new Error('Invalid task ID');
54
+ }
55
+ setupSSE(data.task_id);
56
+ loadHistory();
57
+ promptInput.value = '';
58
+ })
59
+ .catch(error => {
60
+ stepsContainer.innerHTML = `<div class="error">Error: ${error.message}</div>`;
61
+ updateResultPanel({result: error.message}, 'error');
62
+ showResultPanel();
63
+ console.error('Failed to create task:', error);
64
+ });
65
+ }
66
+
67
+ function setupSSE(taskId) {
68
+ let retryCount = 0;
69
+ const maxRetries = 3;
70
+ const retryDelay = 2000;
71
+ let lastResultContent = '';
72
+ let stepsData = [];
73
+
74
+ const stepsContainer = document.getElementById('steps-container');
75
+ const resultContainer = document.getElementById('result-container');
76
+
77
+ // Hide result panel by default
78
+ hideResultPanel();
79
+
80
+ function connect() {
81
+ const eventSource = new EventSource(`/tasks/${taskId}/events`);
82
+ currentEventSource = eventSource;
83
+
84
+ let heartbeatTimer = setInterval(() => {
85
+ const pingDiv = document.createElement('div');
86
+ pingDiv.className = 'ping';
87
+ pingDiv.innerHTML = '·';
88
+ stepsContainer.appendChild(pingDiv);
89
+ }, 5000);
90
+
91
+ // Initial polling
92
+ fetch(`/tasks/${taskId}`)
93
+ .then(response => response.json())
94
+ .then(task => {
95
+ updateTaskStatus(task);
96
+ })
97
+ .catch(error => {
98
+ console.error('Initial status retrieval failed:', error);
99
+ });
100
+
101
+ const handleEvent = (event, type) => {
102
+ clearInterval(heartbeatTimer);
103
+ try {
104
+ const data = JSON.parse(event.data);
105
+ const loadingDiv = stepsContainer.querySelector('.loading');
106
+ if (loadingDiv) loadingDiv.remove();
107
+
108
+ const { formattedContent, timestamp, isoTimestamp } = formatStepContent(data, type);
109
+
110
+ stepsData.push({
111
+ type: type,
112
+ content: formattedContent,
113
+ timestamp: timestamp,
114
+ isoTimestamp: isoTimestamp,
115
+ element: createStepElement(type, formattedContent, timestamp)
116
+ });
117
+
118
+ stepsData.sort((a, b) => {
119
+ return new Date(a.isoTimestamp) - new Date(b.isoTimestamp);
120
+ });
121
+
122
+ stepsContainer.innerHTML = '';
123
+ stepsData.forEach(step => {
124
+ stepsContainer.appendChild(step.element);
125
+ });
126
+
127
+ document.querySelectorAll('.step-item').forEach(item => {
128
+ item.classList.remove('active');
129
+ });
130
+
131
+ const latestStep = stepsData[stepsData.length - 1];
132
+ if (latestStep && latestStep.element) {
133
+ latestStep.element.classList.add('active');
134
+ }
135
+
136
+ autoScroll(stepsContainer);
137
+
138
+ if (type === 'tool' || type === 'act' || type === 'result') {
139
+ updateResultPanel(data, type);
140
+ showResultPanel();
141
+ }
142
+
143
+ fetch(`/tasks/${taskId}`)
144
+ .then(response => response.json())
145
+ .then(task => {
146
+ updateTaskStatus(task);
147
+ })
148
+ .catch(error => {
149
+ console.error('Failed to update status:', error);
150
+ });
151
+ } catch (e) {
152
+ console.error(`Error processing ${type} event:`, e);
153
+ }
154
+ };
155
+
156
+ const eventTypes = ['think', 'tool', 'act', 'log', 'run', 'message'];
157
+ eventTypes.forEach(type => {
158
+ eventSource.addEventListener(type, (event) => handleEvent(event, type));
159
+ });
160
+
161
+ eventSource.addEventListener('complete', (event) => {
162
+ clearInterval(heartbeatTimer);
163
+ try {
164
+ const data = JSON.parse(event.data);
165
+ lastResultContent = data.result || '';
166
+
167
+ const completeDiv = document.createElement('div');
168
+ completeDiv.className = 'complete';
169
+ completeDiv.innerHTML = '<div>✅ Task completed</div>';
170
+ stepsContainer.appendChild(completeDiv);
171
+
172
+ updateResultPanel({result: lastResultContent}, 'complete');
173
+ showResultPanel();
174
+
175
+ fetch(`/tasks/${taskId}`)
176
+ .then(response => response.json())
177
+ .then(task => {
178
+ updateTaskStatus(task);
179
+ })
180
+ .catch(error => {
181
+ console.error('Failed to update final status:', error);
182
+ });
183
+
184
+ eventSource.close();
185
+ currentEventSource = null;
186
+ } catch (e) {
187
+ console.error('Error processing completion event:', e);
188
+ }
189
+ });
190
+
191
+ eventSource.addEventListener('error', (event) => {
192
+ clearInterval(heartbeatTimer);
193
+ try {
194
+ const data = JSON.parse(event.data);
195
+ const errorDiv = document.createElement('div');
196
+ errorDiv.className = 'error';
197
+ errorDiv.innerHTML = `<div>❌ Error: ${data.message}</div>`;
198
+ stepsContainer.appendChild(errorDiv);
199
+
200
+ updateResultPanel({result: data.message}, 'error');
201
+ showResultPanel();
202
+
203
+ eventSource.close();
204
+ currentEventSource = null;
205
+ } catch (e) {
206
+ console.error('Error processing error:', e);
207
+ }
208
+ });
209
+
210
+ eventSource.onerror = (err) => {
211
+ if (eventSource.readyState === EventSource.CLOSED) return;
212
+
213
+ console.error('SSE connection error:', err);
214
+ clearInterval(heartbeatTimer);
215
+ eventSource.close();
216
+
217
+ fetch(`/tasks/${taskId}`)
218
+ .then(response => response.json())
219
+ .then(task => {
220
+ if (task.status === 'completed' || task.status === 'failed') {
221
+ updateTaskStatus(task);
222
+ if (task.status === 'completed') {
223
+ const completeDiv = document.createElement('div');
224
+ completeDiv.className = 'complete';
225
+ completeDiv.innerHTML = '<div>✅ Task completed</div>';
226
+ stepsContainer.appendChild(completeDiv);
227
+
228
+ if (task.steps && task.steps.length > 0) {
229
+ const lastStep = task.steps[task.steps.length - 1];
230
+ updateResultPanel({result: lastStep.result}, 'complete');
231
+ showResultPanel();
232
+ }
233
+ } else {
234
+ const errorDiv = document.createElement('div');
235
+ errorDiv.className = 'error';
236
+ errorDiv.innerHTML = `<div>❌ Error: ${task.error || 'Task failed'}</div>`;
237
+ stepsContainer.appendChild(errorDiv);
238
+
239
+ updateResultPanel({result: task.error || 'Task failed'}, 'error');
240
+ showResultPanel();
241
+ }
242
+ } else if (retryCount < maxRetries) {
243
+ retryCount++;
244
+ const warningDiv = document.createElement('div');
245
+ warningDiv.className = 'warning';
246
+ warningDiv.innerHTML = `<div>⚠ Connection lost, retrying in ${retryDelay/1000} seconds (${retryCount}/${maxRetries})...</div>`;
247
+ stepsContainer.appendChild(warningDiv);
248
+ setTimeout(connect, retryDelay);
249
+ } else {
250
+ const errorDiv = document.createElement('div');
251
+ errorDiv.className = 'error';
252
+ errorDiv.innerHTML = '<div>⚠ Connection lost, please refresh the page</div>';
253
+ stepsContainer.appendChild(errorDiv);
254
+
255
+ updateResultPanel({result: 'Connection lost, please refresh the page'}, 'error');
256
+ showResultPanel();
257
+ }
258
+ })
259
+ .catch(error => {
260
+ console.error('Failed to check task status:', error);
261
+ if (retryCount < maxRetries) {
262
+ retryCount++;
263
+ setTimeout(connect, retryDelay);
264
+ }
265
+ });
266
+ };
267
+ }
268
+
269
+ connect();
270
+ }
271
+
272
+ function updateResultPanel(data, type) {
273
+ const resultContainer = document.getElementById('result-container');
274
+ const currentStep = document.getElementById('current-step');
275
+
276
+ if (!resultContainer || !currentStep) return;
277
+
278
+ // Update top step information
279
+ const typeLabel = getEventLabel(type);
280
+ const icon = getEventIcon(type);
281
+
282
+ // Clear and build new UI
283
+ currentStep.innerHTML = '';
284
+
285
+ // Add icon
286
+ const iconSpan = document.createElement('span');
287
+ iconSpan.className = 'emoji-icon';
288
+ iconSpan.textContent = icon;
289
+ currentStep.appendChild(iconSpan);
290
+
291
+ // Create status text element, add typewriter effect
292
+ const statusText = document.createElement('span');
293
+ statusText.className = 'status-text';
294
+ currentStep.appendChild(statusText);
295
+
296
+ // Typewriter effect displaying status text
297
+ let i = 0;
298
+ let typingEffect = setInterval(() => {
299
+ if (i < typeLabel.length) {
300
+ statusText.textContent += typeLabel.charAt(i);
301
+ i++;
302
+ } else {
303
+ clearInterval(typingEffect);
304
+ }
305
+ }, 50);
306
+
307
+ // Update content area
308
+ let content = '';
309
+
310
+ if (data.result) {
311
+ content = data.result;
312
+ } else if (data.message) {
313
+ content = data.message;
314
+ } else {
315
+ content = JSON.stringify(data, null, 2);
316
+ }
317
+
318
+ // Clear previous content, add new content
319
+ resultContainer.innerHTML = '';
320
+
321
+ // Create content area
322
+ const contentDiv = document.createElement('div');
323
+ contentDiv.classList.add('content-box');
324
+ contentDiv.innerHTML = `<pre>${content}</pre>`;
325
+ resultContainer.appendChild(contentDiv);
326
+
327
+ // Delay adding visible class to trigger fade-in animation
328
+ setTimeout(() => {
329
+ contentDiv.classList.add('visible');
330
+ }, 100);
331
+ }
332
+
333
+ function loadHistory() {
334
+ fetch('/tasks')
335
+ .then(response => {
336
+ if (!response.ok) {
337
+ return response.text().then(text => {
338
+ throw new Error(`Request failed: ${response.status} - ${text.substring(0, 100)}`);
339
+ });
340
+ }
341
+ return response.json();
342
+ })
343
+ .then(tasks => {
344
+ const listContainer = document.getElementById('task-list');
345
+ if (tasks.length === 0) {
346
+ listContainer.innerHTML = '<div class="info">No history tasks</div>';
347
+ return;
348
+ }
349
+
350
+ // Update history count
351
+ const historyCount = document.querySelector('.history-count');
352
+ if (historyCount) {
353
+ historyCount.textContent = tasks.length;
354
+ }
355
+
356
+ listContainer.innerHTML = tasks.map(task => `
357
+ <div class="task-card" data-task-id="${task.id}" onclick="loadTask('${task.id}')">
358
+ <div class="task-title">${task.prompt}</div>
359
+ <div class="task-meta">
360
+ <span>${new Date(task.created_at).toLocaleString()}</span>
361
+ <span class="status status-${task.status ? task.status.toLowerCase() : 'unknown'}">
362
+ ${getStatusText(task.status)}
363
+ </span>
364
+ </div>
365
+ </div>
366
+ `).join('');
367
+ })
368
+ .catch(error => {
369
+ console.error('Failed to load history:', error);
370
+ const listContainer = document.getElementById('task-list');
371
+ listContainer.innerHTML = `<div class="error">Loading failed: ${error.message}</div>`;
372
+ });
373
+ }
374
+
375
+ function loadTask(taskId) {
376
+ if (currentEventSource) {
377
+ currentEventSource.close();
378
+ currentEventSource = null;
379
+ }
380
+
381
+ const taskContainer = document.getElementById('task-container');
382
+ const stepsContainer = document.getElementById('steps-container');
383
+ const resultContainer = document.getElementById('result-container');
384
+
385
+ // Hide welcome message
386
+ const welcomeMessage = taskContainer.querySelector('.welcome-message');
387
+ if (welcomeMessage) {
388
+ welcomeMessage.style.display = 'none';
389
+ }
390
+
391
+ // Hide result panel by default
392
+ hideResultPanel();
393
+
394
+ stepsContainer.innerHTML = '<div class="loading">Loading task...</div>';
395
+ resultContainer.innerHTML = '';
396
+
397
+ // Close history panel on mobile devices
398
+ closeHistoryOnMobile();
399
+
400
+ fetch(`/tasks/${taskId}`)
401
+ .then(response => response.json())
402
+ .then(task => {
403
+ const taskCards = document.querySelectorAll('.task-card');
404
+ taskCards.forEach(card => {
405
+ card.classList.remove('active');
406
+ if (card.getAttribute('data-task-id') === taskId) {
407
+ card.classList.add('active');
408
+ }
409
+ });
410
+
411
+ stepsContainer.innerHTML = '';
412
+ if (task.steps && task.steps.length > 0) {
413
+ // 存储步骤集合
414
+ let taskSteps = [];
415
+
416
+ task.steps.forEach((step, index) => {
417
+ const stepTimestamp = new Date(step.created_at || task.created_at).toLocaleTimeString();
418
+ const stepElement = createStepElement(
419
+ step.type,
420
+ step.result,
421
+ stepTimestamp
422
+ );
423
+
424
+ // 将步骤添加到集合而非直接添加到DOM
425
+ taskSteps.push({
426
+ index: index,
427
+ timestamp: stepTimestamp,
428
+ element: stepElement,
429
+ step: step
430
+ });
431
+ });
432
+
433
+ // 根据时间戳和索引排序步骤
434
+ taskSteps.sort((a, b) => {
435
+ // 尝试使用ISO时间戳进行比较
436
+ try {
437
+ // 如果步骤数据中包含created_at字段,使用它来排序
438
+ if (a.step.created_at && b.step.created_at) {
439
+ return new Date(a.step.created_at) - new Date(b.step.created_at);
440
+ }
441
+ } catch (e) {
442
+ console.error('Error sorting by ISO timestamp:', e);
443
+ }
444
+
445
+ // 首先按时间戳排序
446
+ const timeCompare = new Date(a.timestamp) - new Date(b.timestamp);
447
+ // 如果时间相同,按索引排序
448
+ return timeCompare !== 0 ? timeCompare : a.index - b.index;
449
+ });
450
+
451
+ // 将排序后的步骤添加到容器
452
+ taskSteps.forEach((stepData, index) => {
453
+ // 只将最后一个步骤设为展开状态
454
+ if (index === taskSteps.length - 1) {
455
+ stepData.element.classList.add('expanded');
456
+ stepData.element.classList.add('active');
457
+ }
458
+
459
+ stepsContainer.appendChild(stepData.element);
460
+
461
+ // 显示最后一个步骤的结果
462
+ if (index === taskSteps.length - 1) {
463
+ updateResultPanel({result: stepData.step.result}, stepData.step.type);
464
+ showResultPanel();
465
+ }
466
+ });
467
+ } else {
468
+ stepsContainer.innerHTML = '<div class="info">No steps recorded for this task</div>';
469
+ }
470
+
471
+ updateTaskStatus(task);
472
+ })
473
+ .catch(error => {
474
+ console.error('Failed to load task:', error);
475
+ stepsContainer.innerHTML = `<div class="error">Error: ${error.message}</div>`;
476
+ });
477
+ }
478
+
479
+ function formatStepContent(data, eventType) {
480
+ // 创建具有ISO格式的时间戳,确保排序一致性
481
+ const now = new Date();
482
+ const isoTimestamp = now.toISOString();
483
+ const localTime = now.toLocaleTimeString();
484
+
485
+ return {
486
+ formattedContent: data.result || (data.message || JSON.stringify(data)),
487
+ timestamp: localTime,
488
+ isoTimestamp: isoTimestamp // 添加ISO格式时间戳,用于排序
489
+ };
490
+ }
491
+
492
+ function createStepElement(type, content, timestamp) {
493
+ const step = document.createElement('div');
494
+
495
+ // Executing step
496
+ const stepRegex = /Executing step (\d+)\/(\d+)/;
497
+ if (type === 'log' && stepRegex.test(content)) {
498
+ const match = content.match(stepRegex);
499
+ const currentStep = parseInt(match[1]);
500
+ const totalSteps = parseInt(match[2]);
501
+
502
+ step.className = 'step-divider';
503
+ step.innerHTML = `
504
+ <div class="step-circle">${currentStep}</div>
505
+ <div class="step-line"></div>
506
+ <div class="step-info">${currentStep}/${totalSteps}</div>
507
+ `;
508
+ } else {
509
+ // Get content preview
510
+ let contentPreview = "";
511
+ if (type === 'think' && content.length > 0) {
512
+ // Extract the first 50 characters of the thinking content as preview
513
+ contentPreview = content.substring(0, 50) + (content.length > 50 ? "..." : "");
514
+ } else if (type === 'tool' && content.includes('selected')) {
515
+ // Tool selection content remains as is
516
+ contentPreview = content;
517
+ } else if (type === 'log') {
518
+ // Log content remains as is, usually short
519
+ contentPreview = content;
520
+ } else {
521
+ // Other types take the first 30 characters
522
+ contentPreview = content.substring(0, 30) + (content.length > 30 ? "..." : "");
523
+ }
524
+
525
+ step.className = `step-item ${type}`;
526
+ step.dataset.type = type;
527
+ step.dataset.timestamp = timestamp; // 存储时间戳为数据属性
528
+
529
+ // 增强时间戳显示格式
530
+ const formattedTimestamp = `<time>${timestamp}</time>`;
531
+
532
+ // Use modified layout, remove arrow indicator
533
+ step.innerHTML = `
534
+ <div class="log-header" onclick="toggleStepContent(this)">
535
+ <div class="log-prefix">
536
+ <span class="log-prefix-icon">${getEventIcon(type)}</span>
537
+ [${formattedTimestamp}] ${getEventLabel(type)}
538
+ <span class="content-preview">${contentPreview}</span>
539
+ </div>
540
+ <div class="step-controls">
541
+ <span class="minimize-btn" onclick="minimizeStep(event, this)"></span>
542
+ </div>
543
+ </div>
544
+ <div class="log-body">
545
+ <div class="log-content">
546
+ <pre>${content}</pre>
547
+ </div>
548
+ </div>
549
+ `;
550
+ }
551
+
552
+ // Apply fade-in animation
553
+ step.style.opacity = '0';
554
+ step.style.transform = 'translateY(10px)';
555
+
556
+ setTimeout(() => {
557
+ step.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
558
+ step.style.opacity = '1';
559
+ step.style.transform = 'translateY(0)';
560
+ }, 10);
561
+
562
+ return step;
563
+ }
564
+
565
+ // Toggle display/hide of step content
566
+ function toggleStepContent(header) {
567
+ const stepItem = header.closest('.step-item');
568
+ if (!stepItem) return;
569
+
570
+ const logBody = stepItem.querySelector('.log-body');
571
+ if (!logBody) return;
572
+
573
+ stepItem.classList.toggle('expanded');
574
+
575
+ // Highlight current step
576
+ highlightStep(stepItem);
577
+
578
+ // If expanded, update result panel and show
579
+ if (stepItem.classList.contains('expanded')) {
580
+ const type = stepItem.dataset.type;
581
+ const content = stepItem.querySelector('pre')?.textContent || '';
582
+ updateResultPanel({result: content}, type);
583
+ showResultPanel();
584
+ }
585
+ }
586
+
587
+ // Minimize step
588
+ function minimizeStep(event, btn) {
589
+ event.stopPropagation(); // Prevent event bubbling
590
+
591
+ const stepItem = btn.closest('.step-item');
592
+ if (!stepItem) return;
593
+
594
+ stepItem.classList.toggle('expanded');
595
+ }
596
+
597
+ // Toggle result panel display state
598
+ function toggleResultPanel() {
599
+ const resultPanel = document.getElementById('result-panel');
600
+ const container = document.querySelector('.container');
601
+ if (!resultPanel) return;
602
+
603
+ // If panel is already minimized, fully display
604
+ if (resultPanel.classList.contains('minimized')) {
605
+ resultPanel.classList.remove('minimized');
606
+ container.classList.add('with-result');
607
+ } else {
608
+ // Otherwise minimize panel
609
+ resultPanel.classList.add('minimized');
610
+ container.classList.remove('with-result');
611
+ }
612
+ }
613
+
614
+ // Hide result panel
615
+ function hideResultPanel() {
616
+ const resultPanel = document.getElementById('result-panel');
617
+ const container = document.querySelector('.container');
618
+ if (resultPanel) {
619
+ resultPanel.classList.add('hidden');
620
+ resultPanel.classList.remove('minimized'); // Ensure minimized state is reset when hiding
621
+ container.classList.remove('with-result'); // Remove container style
622
+ }
623
+ }
624
+
625
+ // Show result panel
626
+ function showResultPanel() {
627
+ const resultPanel = document.getElementById('result-panel');
628
+ const container = document.querySelector('.container');
629
+ if (resultPanel) {
630
+ resultPanel.classList.remove('hidden');
631
+ resultPanel.classList.remove('minimized'); // Ensure not minimized when showing
632
+ container.classList.add('with-result'); // Add container style
633
+ }
634
+ }
635
+
636
+ function autoScroll(element) {
637
+ requestAnimationFrame(() => {
638
+ element.scrollTo({
639
+ top: element.scrollHeight,
640
+ behavior: 'smooth'
641
+ });
642
+ });
643
+ setTimeout(() => {
644
+ element.scrollTop = element.scrollHeight;
645
+ }, 100);
646
+ }
647
+
648
+ function getEventIcon(type) {
649
+ switch (type) {
650
+ case 'think': return '🤔';
651
+ case 'tool': return '🛠️';
652
+ case 'act': return '🚀';
653
+ case 'log': return '📝';
654
+ case 'run': return '▶️';
655
+ case 'message': return '💬';
656
+ case 'complete': return '✅';
657
+ case 'error': return '❌';
658
+ default: return '📌';
659
+ }
660
+ }
661
+
662
+ function getEventLabel(type) {
663
+ switch (type) {
664
+ case 'think': return 'Thinking';
665
+ case 'tool': return 'Using Tool';
666
+ case 'act': return 'Taking Action';
667
+ case 'log': return 'Log';
668
+ case 'run': return 'Running';
669
+ case 'message': return 'Message';
670
+ case 'complete': return 'Completed';
671
+ case 'error': return 'Error';
672
+ default: return 'Step';
673
+ }
674
+ }
675
+
676
+ function updateTaskStatus(task) {
677
+ const statusBar = document.getElementById('status-bar');
678
+ if (!statusBar) return;
679
+
680
+ if (task.status === 'completed') {
681
+ statusBar.innerHTML = `<span class="status-complete">✅ Task completed</span>`;
682
+
683
+ if (currentEventSource) {
684
+ currentEventSource.close();
685
+ currentEventSource = null;
686
+ }
687
+ } else if (task.status === 'failed') {
688
+ statusBar.innerHTML = `<span class="status-error">❌ Task failed: ${task.error || 'Unknown error'}</span>`;
689
+
690
+ if (currentEventSource) {
691
+ currentEventSource.close();
692
+ currentEventSource = null;
693
+ }
694
+ } else {
695
+ statusBar.innerHTML = `<span class="status-running">⚙️ Task running: ${task.status}</span>`;
696
+ }
697
+ }
698
+
699
+ function showFullImage(imageSrc) {
700
+ let modal = document.getElementById('image-modal');
701
+ if (!modal) {
702
+ modal = document.createElement('div');
703
+ modal.id = 'image-modal';
704
+ modal.className = 'image-modal';
705
+ modal.innerHTML = `
706
+ <span class="close-modal">&times;</span>
707
+ <img src="${imageSrc}" class="modal-content" id="full-image">
708
+ `;
709
+ document.body.appendChild(modal);
710
+
711
+ const closeBtn = modal.querySelector('.close-modal');
712
+ closeBtn.addEventListener('click', () => {
713
+ modal.classList.remove('active');
714
+ });
715
+
716
+ modal.addEventListener('click', (e) => {
717
+ if (e.target === modal) {
718
+ modal.classList.remove('active');
719
+ }
720
+ });
721
+ } else {
722
+ document.getElementById('full-image').src = imageSrc;
723
+ }
724
+
725
+ modal.classList.add('active');
726
+ }
727
+
728
+ function simulateRunPython(filePath) {
729
+ let modal = document.getElementById('python-modal');
730
+ if (!modal) {
731
+ modal = document.createElement('div');
732
+ modal.id = 'python-modal';
733
+ modal.className = 'python-modal';
734
+ modal.innerHTML = `
735
+ <div class="python-console">
736
+ <div class="close-modal">&times;</div>
737
+ <div class="python-output">Loading Python file content...</div>
738
+ </div>
739
+ `;
740
+ document.body.appendChild(modal);
741
+
742
+ const closeBtn = modal.querySelector('.close-modal');
743
+ closeBtn.addEventListener('click', () => {
744
+ modal.classList.remove('active');
745
+ });
746
+ }
747
+
748
+ modal.classList.add('active');
749
+
750
+ // Load Python file content
751
+ fetch(filePath)
752
+ .then(response => response.text())
753
+ .then(code => {
754
+ const outputDiv = modal.querySelector('.python-output');
755
+ outputDiv.innerHTML = '';
756
+
757
+ const codeElement = document.createElement('pre');
758
+ codeElement.textContent = code;
759
+ codeElement.style.marginBottom = '20px';
760
+ codeElement.style.padding = '10px';
761
+ codeElement.style.borderBottom = '1px solid #444';
762
+ outputDiv.appendChild(codeElement);
763
+
764
+ // Add simulation run results
765
+ const resultElement = document.createElement('div');
766
+ resultElement.innerHTML = `
767
+ <div style="color: #4CAF50; margin-top: 10px; margin-bottom: 10px;">
768
+ > Simulation run output results:</div>
769
+ <pre style="color: #f8f8f8;">
770
+ # This is the simulation run output results
771
+ # Actual run results may vary
772
+
773
+ # Running ${filePath.split('/').pop()}...
774
+ print("Hello from Python Simulated environment!")
775
+
776
+ # Code execution completed
777
+ </pre>
778
+ `;
779
+ outputDiv.appendChild(resultElement);
780
+ })
781
+ .catch(error => {
782
+ console.error('Failed to load Python file:', error);
783
+ const outputDiv = modal.querySelector('.python-output');
784
+ outputDiv.innerHTML = `File loading error: ${error.message}`;
785
+ });
786
+ }
787
+
788
+ // Highlight current selected step
789
+ function highlightStep(stepElement) {
790
+ // Remove highlight from other steps
791
+ document.querySelectorAll('.step-item').forEach(item => {
792
+ item.classList.remove('active');
793
+ });
794
+
795
+ // Add highlight to current step
796
+ stepElement.classList.add('active');
797
+ }
798
+
799
+ // Toggle history panel display state
800
+ function toggleHistory() {
801
+ const historyPanel = document.querySelector('.history-panel');
802
+ const overlay = document.querySelector('.overlay');
803
+ const historyToggle = document.querySelector('.history-toggle');
804
+ const container = document.querySelector('.container');
805
+
806
+ if (historyVisible) {
807
+ // Hide history
808
+ historyPanel.classList.remove('show');
809
+ overlay.classList.remove('show');
810
+ historyToggle.classList.remove('active');
811
+ container.classList.remove('with-history');
812
+ } else {
813
+ // Show history
814
+ historyPanel.classList.add('show');
815
+ overlay.classList.add('show');
816
+ historyToggle.classList.add('active');
817
+ // Add spacing on large screens
818
+ if (window.innerWidth > 768) {
819
+ container.classList.add('with-history');
820
+ }
821
+ }
822
+
823
+ historyVisible = !historyVisible;
824
+ }
825
+
826
+ // Close history panel on small screens
827
+ function closeHistoryOnMobile() {
828
+ if (window.innerWidth <= 768 && historyVisible) {
829
+ toggleHistory();
830
+ }
831
+ }
832
+
833
+ // Get status text
834
+ function getStatusText(status) {
835
+ switch (status) {
836
+ case 'pending': return 'Pending';
837
+ case 'running': return 'Running';
838
+ case 'completed': return 'Completed';
839
+ case 'failed': return 'Failed';
840
+ default: return 'Unknown';
841
+ }
842
+ }
843
+
844
+ // Initialize interface
845
+ document.addEventListener('DOMContentLoaded', () => {
846
+ // Add history toggle logic
847
+ const historyToggle = document.querySelector('.history-toggle');
848
+ if (historyToggle) {
849
+ historyToggle.addEventListener('click', toggleHistory);
850
+ }
851
+
852
+ // Add overlay click to close history
853
+ const overlay = document.querySelector('.overlay');
854
+ if (overlay) {
855
+ overlay.addEventListener('click', toggleHistory);
856
+ }
857
+
858
+ // Load history
859
+ loadHistory();
860
+
861
+ // Bind input field events
862
+ document.getElementById('prompt-input').addEventListener('keydown', (e) => {
863
+ if (e.key === 'Enter' && !e.shiftKey) {
864
+ e.preventDefault();
865
+ createTask();
866
+ }
867
+ });
868
+
869
+ // Listen for window size changes
870
+ window.addEventListener('resize', () => {
871
+ const container = document.querySelector('.container');
872
+
873
+ // Maintain history sidebar effect on large screens, remove on small screens
874
+ if (window.innerWidth > 768 && historyVisible) {
875
+ container.classList.add('with-history');
876
+ } else {
877
+ container.classList.remove('with-history');
878
+ }
879
+ });
880
+
881
+ // Add keyboard event listener to close modal
882
+ document.addEventListener('keydown', (e) => {
883
+ // ESC key closes history panel
884
+ if (e.key === 'Escape') {
885
+ if (historyVisible) {
886
+ toggleHistory();
887
+ }
888
+
889
+ const imageModal = document.getElementById('image-modal');
890
+ if (imageModal && imageModal.classList.contains('active')) {
891
+ imageModal.classList.remove('active');
892
+ }
893
+
894
+ const pythonModal = document.getElementById('python-modal');
895
+ if (pythonModal && pythonModal.classList.contains('active')) {
896
+ pythonModal.classList.remove('active');
897
+ }
898
+ }
899
+ });
900
+ });
static/themes/openmanus/static/style.css ADDED
@@ -0,0 +1,1630 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --primary-color: #007bff;
3
+ --primary-hover: #0056b3;
4
+ --primary-color-light: #e6f2ff;
5
+ --success-color: #28a745;
6
+ --success-color-light: #e8f5e9;
7
+ --error-color: #dc3545;
8
+ --error-color-light: #ffe6e6;
9
+ --warning-color: #ff9800;
10
+ --warning-color-light: #fff8e6;
11
+ --info-color: #2196f3;
12
+ --info-color-light: #e3f2fd;
13
+ --text-color: #333;
14
+ --text-light: #666;
15
+ --bg-color: #f8f9fa;
16
+ --border-color: #ddd;
17
+ }
18
+
19
+ * {
20
+ box-sizing: border-box;
21
+ margin: 0;
22
+ padding: 0;
23
+ }
24
+
25
+ body {
26
+ font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
27
+ margin: 0;
28
+ padding: 0;
29
+ background-color: var(--bg-color);
30
+ color: var(--text-color);
31
+ }
32
+
33
+ .container {
34
+ display: flex;
35
+ min-height: 100vh;
36
+ min-width: 0;
37
+ width: 98%;
38
+ margin: 0 auto;
39
+ padding: 10px;
40
+ gap: 10px;
41
+ position: relative;
42
+ transition: all 0.3s ease;
43
+ margin-top: 60px; /* Top header height + spacing */
44
+ min-height: calc(100vh - 60px);
45
+ }
46
+
47
+ .container.with-result {
48
+ /* Reserve space for result panel, use calc to calculate width, reduce gap */
49
+ width: calc(68% - 10px); /* Increase main panel width, reduce right margin */
50
+ margin-right: auto;
51
+ margin-left: 0;
52
+ }
53
+
54
+ .card {
55
+ background-color: white;
56
+ border-radius: 8px;
57
+ padding: 20px;
58
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
59
+ }
60
+
61
+ .history-panel {
62
+ width: 200px;
63
+ flex-shrink: 0;
64
+ background-color: white;
65
+ border-radius: 8px;
66
+ padding: 15px;
67
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
68
+ height: calc(100vh - 80px); /* 减去标题栏高度和间距 */
69
+ overflow: auto;
70
+ }
71
+
72
+ .steps-panel {
73
+ width: 300px;
74
+ flex-shrink: 0;
75
+ background-color: white;
76
+ border-radius: 8px;
77
+ padding: 15px;
78
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
79
+ height: calc(100vh - 80px); /* 减去标题栏高度和间距 */
80
+ overflow: auto;
81
+ }
82
+
83
+ .steps-container {
84
+ flex: 1;
85
+ width: 100%;
86
+ overflow-y: auto;
87
+ overflow-x: hidden;
88
+ }
89
+
90
+ .main-panel {
91
+ flex: 1;
92
+ display: flex;
93
+ flex-direction: column;
94
+ gap: 10px;
95
+ height: calc(100vh - 80px); /* 减去标题栏高度和间距 */
96
+ min-width: 400px;
97
+ position: relative;
98
+ transition: all 0.3s ease;
99
+ }
100
+
101
+ .task-container {
102
+ flex: 1;
103
+ width: 100%;
104
+ max-width: 100%;
105
+ position: relative;
106
+ display: flex;
107
+ flex-direction: column;
108
+ justify-content: center;
109
+ background-color: white;
110
+ border-radius: 8px;
111
+ padding: 15px;
112
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
113
+ overflow: auto;
114
+ transition: width 0.3s ease;
115
+ }
116
+
117
+ .result-panel {
118
+ width: 31%; /* Slightly reduce result panel width */
119
+ min-width: 380px; /* Reduce minimum width */
120
+ height: calc(100vh - 80px); /* Subtract header height and spacing */
121
+ position: fixed;
122
+ right: 10px; /* Restore right position */
123
+ top: 70px; /* Adjust to fully align with history panel */
124
+ background-color: rgba(22, 24, 36, 0.98);
125
+ border: 1px solid rgba(60, 80, 220, 0.2);
126
+ border-radius: 8px;
127
+ padding: 12px;
128
+ box-shadow: 0 5px 25px rgba(0, 0, 0, 0.3), 0 0 40px rgba(60, 80, 220, 0.15);
129
+ overflow: auto;
130
+ transition: transform 0.3s ease;
131
+ z-index: 10;
132
+ display: flex;
133
+ flex-direction: column;
134
+ }
135
+
136
+ .result-panel.hidden {
137
+ transform: translateX(calc(100% + 10px)); /* Restore slide-out effect to the right */
138
+ }
139
+
140
+ .result-panel.minimized {
141
+ display: none !important;
142
+ }
143
+
144
+ .result-header {
145
+ display: flex;
146
+ justify-content: space-between;
147
+ align-items: center;
148
+ margin-bottom: 12px;
149
+ padding-bottom: 12px;
150
+ border-bottom: 1px solid rgba(80, 80, 80, 0.3);
151
+ background: linear-gradient(90deg, rgba(20, 25, 30, 0.9), rgba(30, 35, 45, 0.9));
152
+ padding: 15px;
153
+ border-radius: 8px 8px 0 0;
154
+ position: relative;
155
+ overflow: hidden;
156
+ }
157
+
158
+ .result-header::after {
159
+ content: '';
160
+ position: absolute;
161
+ bottom: 0;
162
+ left: 0;
163
+ width: 100%;
164
+ height: 1px;
165
+ background: linear-gradient(90deg,
166
+ transparent,
167
+ rgba(0, 180, 255, 0.4),
168
+ rgba(120, 0, 255, 0.6),
169
+ rgba(0, 180, 255, 0.4),
170
+ transparent
171
+ );
172
+ }
173
+
174
+ .result-header h2 {
175
+ font-size: 18px;
176
+ font-weight: 500;
177
+ color: #fff;
178
+ margin: 0;
179
+ position: relative;
180
+ text-shadow: 0 0 10px rgba(0, 140, 255, 0.3);
181
+ display: flex;
182
+ align-items: center;
183
+ }
184
+
185
+ .result-header h2::before {
186
+ content: '';
187
+ display: inline-block;
188
+ width: 10px;
189
+ height: 10px;
190
+ background-color: rgba(0, 180, 255, 0.8);
191
+ border-radius: 50%;
192
+ margin-right: 10px;
193
+ box-shadow: 0 0 8px rgba(0, 180, 255, 0.8);
194
+ animation: pulse-light 2s infinite;
195
+ }
196
+
197
+ .result-controls {
198
+ display: flex;
199
+ gap: 8px;
200
+ }
201
+
202
+ .minimize-result {
203
+ display: inline-flex;
204
+ width: 28px;
205
+ height: 28px;
206
+ justify-content: center;
207
+ align-items: center;
208
+ border-radius: 4px;
209
+ cursor: pointer;
210
+ user-select: none;
211
+ transition: all 0.2s;
212
+ position: relative;
213
+ background: rgba(255, 255, 255, 0.05);
214
+ border: 1px solid rgba(255, 255, 255, 0.1);
215
+ }
216
+
217
+ .minimize-result:hover {
218
+ background: rgba(255, 255, 255, 0.15);
219
+ transform: scale(1.05);
220
+ box-shadow: 0 0 10px rgba(0, 140, 255, 0.4);
221
+ }
222
+
223
+ /* 替换箭头为全屏图标 */
224
+ .minimize-result::before,
225
+ .minimize-result::after {
226
+ content: "";
227
+ position: absolute;
228
+ background-color: rgba(255, 255, 255, 0.8);
229
+ transition: all 0.2s;
230
+ }
231
+
232
+ /* 创建全屏图标的外框 */
233
+ .minimize-result::before {
234
+ width: 12px;
235
+ height: 12px;
236
+ border: 1px solid rgba(255, 255, 255, 0.8);
237
+ background: transparent;
238
+ }
239
+
240
+ /* 创建全屏图标的右下角小方块 */
241
+ .minimize-result::after {
242
+ width: 5px;
243
+ height: 5px;
244
+ background-color: rgba(255, 255, 255, 0.8);
245
+ right: 7px;
246
+ bottom: 7px;
247
+ }
248
+
249
+ .result-container {
250
+ width: 100%;
251
+ flex: 1;
252
+ overflow: auto;
253
+ margin-top: 0;
254
+ padding: 5px;
255
+ font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
256
+ background-color: transparent;
257
+ color: rgba(255, 255, 255, 0.85);
258
+ }
259
+
260
+ .result-container p,
261
+ .result-container div,
262
+ .result-container pre,
263
+ .result-container span {
264
+ white-space: pre-wrap;
265
+ word-wrap: break-word;
266
+ max-width: 100%;
267
+ margin-bottom: 5px;
268
+ line-height: 1.4;
269
+ }
270
+
271
+ /* Modified search result styles */
272
+ .search-result-item {
273
+ padding: 10px;
274
+ border-bottom: 1px solid #eee;
275
+ cursor: pointer;
276
+ }
277
+
278
+ .search-result-item:hover {
279
+ background-color: #f0f0f0;
280
+ }
281
+
282
+ .search-result-title {
283
+ font-weight: 500;
284
+ color: #1a0dab;
285
+ margin-bottom: 3px;
286
+ }
287
+
288
+ .search-result-url {
289
+ color: #006621;
290
+ font-size: 0.8rem;
291
+ margin-bottom: 3px;
292
+ }
293
+
294
+ .search-result-description {
295
+ color: #545454;
296
+ font-size: 0.9rem;
297
+ }
298
+
299
+ /* Add search box styles */
300
+ .search-box {
301
+ display: flex;
302
+ align-items: center;
303
+ margin-bottom: 10px;
304
+ padding: 8px;
305
+ background-color: #f5f5f5;
306
+ border-radius: 4px;
307
+ border: 1px solid #e0e0e0;
308
+ }
309
+
310
+ .search-box-icon {
311
+ color: #777;
312
+ margin-right: 8px;
313
+ }
314
+
315
+ .search-input {
316
+ flex: 1;
317
+ border: none;
318
+ background: transparent;
319
+ outline: none;
320
+ font-size: 14px;
321
+ color: #333;
322
+ }
323
+
324
+ .search-box .search-button {
325
+ background-color: #f5f5f5;
326
+ color: #777;
327
+ border: none;
328
+ padding: 4px 8px;
329
+ border-radius: 4px;
330
+ cursor: pointer;
331
+ font-size: 14px;
332
+ }
333
+
334
+ .search-box .search-button:hover {
335
+ background-color: #e0e0e0;
336
+ }
337
+
338
+ .task-list {
339
+ margin-top: 10px;
340
+ max-height: calc(100% - 40px);
341
+ overflow-y: auto;
342
+ overflow-x: hidden;
343
+ }
344
+
345
+ .welcome-message {
346
+ display: flex;
347
+ flex-direction: column;
348
+ justify-content: center;
349
+ align-items: center;
350
+ text-align: center;
351
+ color: var(--text-light);
352
+ padding: 40px 20px;
353
+ width: 100%;
354
+ height: 100%;
355
+ min-height: 400px;
356
+ position: relative;
357
+ margin: auto 0;
358
+ }
359
+
360
+ .welcome-message h1 {
361
+ font-size: 2.5rem;
362
+ margin-bottom: 20px;
363
+ color: #333;
364
+ font-weight: 600;
365
+ }
366
+
367
+ .logo-animation {
368
+ margin-bottom: 10px;
369
+ animation: pulse 2s infinite ease-in-out;
370
+ }
371
+
372
+ .welcome-logo {
373
+ width: 320px;
374
+ height: auto;
375
+ filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.2));
376
+ transition: all 0.3s ease;
377
+ margin-bottom: 5px;
378
+ }
379
+
380
+ .welcome-logo:hover {
381
+ transform: scale(1.05);
382
+ filter: drop-shadow(0 12px 30px rgba(0, 0, 0, 0.3));
383
+ }
384
+
385
+ .animated-text {
386
+ font-size: 1.8rem;
387
+ margin-bottom: 16px;
388
+ color: var(--primary-color);
389
+ animation: fadeIn 1s ease-in-out;
390
+ animation-delay: 0.3s;
391
+ animation-fill-mode: both;
392
+ }
393
+
394
+ .animated-subtext {
395
+ font-size: 0.9rem;
396
+ color: #666;
397
+ animation: fadeIn 1s ease-in-out;
398
+ animation-delay: 0.6s;
399
+ animation-fill-mode: both;
400
+ position: relative;
401
+ overflow: hidden;
402
+ }
403
+
404
+ .animated-subtext::after {
405
+ content: '';
406
+ position: absolute;
407
+ bottom: 0;
408
+ left: 0;
409
+ width: 100%;
410
+ height: 1px;
411
+ background: linear-gradient(90deg,
412
+ transparent,
413
+ rgba(0, 180, 255, 0.4),
414
+ rgba(120, 0, 255, 0.6),
415
+ rgba(0, 180, 255, 0.4),
416
+ transparent
417
+ );
418
+ animation: shimmer 3s infinite;
419
+ }
420
+
421
+ @keyframes shimmer {
422
+ 0% { transform: translateX(-100%); }
423
+ 100% { transform: translateX(100%); }
424
+ }
425
+
426
+ @keyframes pulse {
427
+ 0% {
428
+ transform: scale(1);
429
+ }
430
+ 50% {
431
+ transform: scale(1.05);
432
+ }
433
+ 100% {
434
+ transform: scale(1);
435
+ }
436
+ }
437
+
438
+ @keyframes fadeIn {
439
+ from {
440
+ opacity: 0;
441
+ transform: translateY(15px);
442
+ }
443
+ to {
444
+ opacity: 1;
445
+ transform: translateY(0);
446
+ }
447
+ }
448
+
449
+ /* 高亮文本 - 亮色系蓝色渐变 */
450
+ .highlight-text {
451
+ background: linear-gradient(135deg, #0575E6 0%, #0096FF 35%, #00B4FF 65%, #00D2FF 100%);
452
+ -webkit-background-clip: text;
453
+ background-clip: text;
454
+ -webkit-text-fill-color: transparent;
455
+ font-weight: 600;
456
+ letter-spacing: 0.5px;
457
+ text-shadow: 0 0 8px rgba(5, 117, 230, 0.3), 0 0 15px rgba(0, 198, 251, 0.2);
458
+ }
459
+
460
+ /* Login button - blue border color scheme */
461
+ .login-btn {
462
+ background: linear-gradient(135deg, #0575E6, #0096FF);
463
+ color: white;
464
+ padding: 10px 24px;
465
+ border-radius: 30px;
466
+ font-weight: 500;
467
+ font-size: 14px;
468
+ transition: all 0.25s ease;
469
+ display: flex;
470
+ align-items: center;
471
+ gap: 8px;
472
+ border: none;
473
+ cursor: pointer;
474
+ text-decoration: none;
475
+ box-shadow: 0 4px 15px rgba(5, 117, 230, 0.2);
476
+ }
477
+
478
+ .login-btn:hover {
479
+ background: linear-gradient(135deg, #0468C8, #0086E8);
480
+ transform: translateY(-2px);
481
+ box-shadow: 0 6px 20px rgba(5, 117, 230, 0.3);
482
+ }
483
+
484
+ .login-btn:active {
485
+ transform: translateY(0px);
486
+ box-shadow: 0 2px 10px rgba(5, 117, 230, 0.15);
487
+ }
488
+
489
+ /* Send button styles - blue border color scheme */
490
+ .send-btn {
491
+ padding: 12px 30px;
492
+ background: linear-gradient(135deg, #0575E6, #0096FF);
493
+ color: white;
494
+ border: none;
495
+ border-radius: 30px;
496
+ cursor: pointer;
497
+ font-size: 15px;
498
+ font-weight: 500;
499
+ letter-spacing: 0.5px;
500
+ transition: all 0.25s ease;
501
+ box-shadow: 0 4px 15px rgba(5, 117, 230, 0.2);
502
+ }
503
+
504
+ .send-btn:hover {
505
+ background: linear-gradient(135deg, #0468C8, #0086E8);
506
+ transform: translateY(-2px);
507
+ box-shadow: 0 6px 20px rgba(5, 117, 230, 0.3);
508
+ }
509
+
510
+ .send-btn:active {
511
+ transform: translateY(0px);
512
+ box-shadow: 0 2px 10px rgba(5, 117, 230, 0.15);
513
+ }
514
+
515
+ .task-card {
516
+ background: #fff;
517
+ padding: 15px;
518
+ margin-bottom: 10px;
519
+ border-radius: 8px;
520
+ cursor: pointer;
521
+ transition: all 0.2s;
522
+ }
523
+
524
+ .task-card:hover {
525
+ transform: translateX(5px);
526
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
527
+ }
528
+
529
+ .task-card.active {
530
+ border-left: 4px solid var(--primary-color);
531
+ background-color: var(--primary-color-light);
532
+ }
533
+
534
+ .status-pending {
535
+ color: var(--text-light);
536
+ }
537
+
538
+ .status-running {
539
+ color: var(--primary-color);
540
+ }
541
+
542
+ .status-completed {
543
+ color: var(--success-color);
544
+ }
545
+
546
+ .status-failed {
547
+ color: var(--error-color);
548
+ }
549
+
550
+ .status-text {
551
+ margin-left: 5px;
552
+ position: relative;
553
+ color: rgba(255, 255, 255, 1); /* 确保文字是纯白色 */
554
+ font-weight: 500;
555
+ }
556
+
557
+ .status-text::after {
558
+ content: '|';
559
+ position: absolute;
560
+ right: -12px;
561
+ color: rgba(0, 140, 255, 0.9); /* 蓝色光标 */
562
+ animation: blink 1s infinite;
563
+ }
564
+
565
+ @keyframes blink {
566
+ 0%, 100% {
567
+ opacity: 1;
568
+ }
569
+ 50% {
570
+ opacity: 0;
571
+ }
572
+ }
573
+
574
+ .step-item {
575
+ padding: 0;
576
+ background: white;
577
+ border: 1px solid #eee;
578
+ border-radius: 8px;
579
+ width: 100%;
580
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
581
+ margin-bottom: 8px;
582
+ opacity: 1;
583
+ transform: none;
584
+ overflow: hidden;
585
+ transition: all 0.3s ease;
586
+ }
587
+
588
+ .step-item .log-header {
589
+ display: flex;
590
+ justify-content: space-between;
591
+ align-items: center;
592
+ padding: 8px 12px;
593
+ cursor: pointer;
594
+ background-color: #f8f9fa;
595
+ border-bottom: 1px solid #eee;
596
+ transition: all 0.3s ease;
597
+ color: #333;
598
+ position: relative;
599
+ overflow: hidden;
600
+ }
601
+
602
+ .step-item .log-body {
603
+ display: none; /* 默认隐藏详细内容 */
604
+ padding: 10px;
605
+ background-color: white;
606
+ color: #333;
607
+ }
608
+
609
+ .log-prefix {
610
+ color: #444;
611
+ display: flex;
612
+ align-items: center;
613
+ font-size: 0.9em;
614
+ flex: 1;
615
+ min-width: 0; /* 允许flex项目收缩 */
616
+ }
617
+
618
+ /* 增强时间戳显示 */
619
+ .log-prefix time {
620
+ font-weight: 500;
621
+ color: #0575E6;
622
+ padding: 0 5px;
623
+ background-color: rgba(5, 117, 230, 0.05);
624
+ border-radius: 3px;
625
+ }
626
+
627
+ .content-preview {
628
+ margin-left: 10px;
629
+ white-space: nowrap;
630
+ overflow: hidden;
631
+ text-overflow: ellipsis;
632
+ max-width: 60%;
633
+ opacity: 0.8;
634
+ font-size: 0.9em;
635
+ }
636
+
637
+ /* 步骤图标 */
638
+ .log-prefix-icon {
639
+ display: inline-flex;
640
+ width: 24px;
641
+ height: 24px;
642
+ justify-content: center;
643
+ align-items: center;
644
+ background: #f0f0f0;
645
+ border-radius: 50%;
646
+ margin-right: 8px;
647
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
648
+ border: 1px solid #eee;
649
+ color: #333;
650
+ flex-shrink: 0;
651
+ }
652
+
653
+ .step-controls {
654
+ display: flex;
655
+ }
656
+
657
+ .minimize-btn {
658
+ display: inline-flex;
659
+ width: 22px;
660
+ height: 22px;
661
+ justify-content: center;
662
+ align-items: center;
663
+ background: #f0f0f0;
664
+ border: 1px solid #e0e0e0;
665
+ border-radius: 50%;
666
+ cursor: pointer;
667
+ user-select: none;
668
+ color: #555;
669
+ transition: all 0.2s;
670
+ font-size: 12px;
671
+ }
672
+
673
+ .minimize-btn:hover {
674
+ background: #e0e0e0;
675
+ color: #333;
676
+ }
677
+
678
+ /* 不同步骤类型的颜色 */
679
+ .step-item.think .log-header {
680
+ background-color: var(--info-color-light);
681
+ border-left: 3px solid var(--info-color);
682
+ }
683
+
684
+ .step-item.tool .log-header {
685
+ background-color: var(--warning-color-light);
686
+ border-left: 3px solid var(--warning-color);
687
+ }
688
+
689
+ .step-item.act .log-header {
690
+ background-color: var(--primary-color-light);
691
+ border-left: 3px solid var(--primary-color);
692
+ }
693
+
694
+ .step-item.log .log-header {
695
+ background-color: #f8f9fa;
696
+ border-left: 3px solid #ddd;
697
+ }
698
+
699
+ .step-item.expanded .log-body {
700
+ display: block; /* 展开时才显示详细内容 */
701
+ }
702
+
703
+ .step-item pre {
704
+ margin: 0;
705
+ white-space: pre-wrap;
706
+ word-break: break-word;
707
+ font-size: 0.9em;
708
+ line-height: 1.4;
709
+ padding: 10px;
710
+ border-radius: 4px;
711
+ background: var(--bg-color);
712
+ }
713
+
714
+ .step-item pre.think {
715
+ background: var(--info-color-light);
716
+ border-left: 4px solid var(--info-color);
717
+ }
718
+
719
+ .step-item pre.tool {
720
+ background: var(--warning-color-light);
721
+ border-left: 4px solid var(--warning-color);
722
+ }
723
+
724
+ .step-item pre.act {
725
+ background: var(--primary-color-light);
726
+ border-left: 4px solid var(--primary-color);
727
+ }
728
+
729
+ .step-item pre.result {
730
+ background: var(--success-color-light);
731
+ border-left: 4px solid var(--success-color);
732
+ }
733
+
734
+ .step-item pre.error {
735
+ background: var(--error-color-light);
736
+ border-left: 4px solid var(--error-color);
737
+ }
738
+
739
+ .loading {
740
+ padding: 15px;
741
+ color: #666;
742
+ text-align: center;
743
+ }
744
+
745
+ .ping {
746
+ color: #ccc;
747
+ text-align: center;
748
+ margin: 5px 0;
749
+ height: 10px;
750
+ display: block;
751
+ }
752
+
753
+ .error {
754
+ color: #dc3545;
755
+ padding: 10px;
756
+ background: #ffe6e6;
757
+ border-radius: 4px;
758
+ margin: 10px 0;
759
+ }
760
+
761
+ .complete {
762
+ color: #28a745;
763
+ padding: 10px;
764
+ background: #e6ffe6;
765
+ border-radius: 4px;
766
+ margin: 10px 0;
767
+ }
768
+
769
+ .info {
770
+ color: #17a2b8;
771
+ padding: 10px;
772
+ background: #e3f2fd;
773
+ border-radius: 4px;
774
+ margin: 10px 0;
775
+ }
776
+
777
+ /* Step division line style */
778
+ .step-divider {
779
+ display: flex;
780
+ align-items: center;
781
+ width: 100%;
782
+ margin: 15px 0;
783
+ position: relative;
784
+ }
785
+
786
+ .step-circle {
787
+ width: 36px;
788
+ height: 36px;
789
+ border-radius: 50%;
790
+ background-color: var(--primary-color);
791
+ color: white;
792
+ display: flex;
793
+ align-items: center;
794
+ justify-content: center;
795
+ font-weight: bold;
796
+ font-size: 1.2em;
797
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
798
+ z-index: 2;
799
+ flex-shrink: 0;
800
+ }
801
+
802
+ /* File interaction style */
803
+ .file-interaction {
804
+ margin-top: 15px;
805
+ padding: 10px;
806
+ border-radius: 6px;
807
+ background-color: #f5f7fa;
808
+ border: 1px solid var(--border-color);
809
+ }
810
+
811
+ .download-link {
812
+ display: inline-block;
813
+ padding: 8px 16px;
814
+ background-color: var(--primary-color);
815
+ color: white;
816
+ text-decoration: none;
817
+ border-radius: 4px;
818
+ font-size: 0.9em;
819
+ transition: background-color 0.2s;
820
+ }
821
+
822
+ .download-link:hover {
823
+ background-color: var(--primary-hover);
824
+ }
825
+
826
+ .preview-image {
827
+ max-width: 100%;
828
+ max-height: 200px;
829
+ margin-bottom: 10px;
830
+ border-radius: 4px;
831
+ cursor: pointer;
832
+ transition: transform 0.2s;
833
+ }
834
+
835
+ .preview-image:hover {
836
+ transform: scale(1.02);
837
+ }
838
+
839
+ .audio-player {
840
+ display: flex;
841
+ flex-direction: column;
842
+ gap: 10px;
843
+ }
844
+
845
+ .audio-player audio {
846
+ width: 100%;
847
+ margin-bottom: 10px;
848
+ }
849
+
850
+ .run-button {
851
+ display: inline-block;
852
+ padding: 8px 16px;
853
+ background-color: var(--success-color);
854
+ color: white;
855
+ border: none;
856
+ border-radius: 4px;
857
+ cursor: pointer;
858
+ font-size: 0.9em;
859
+ margin-right: 10px;
860
+ transition: background-color 0.2s;
861
+ }
862
+
863
+ .run-button:hover {
864
+ background-color: #218838;
865
+ }
866
+
867
+ /* Full screen image modal box */
868
+ .image-modal {
869
+ display: none;
870
+ position: fixed;
871
+ top: 0;
872
+ left: 0;
873
+ width: 100%;
874
+ height: 100%;
875
+ background-color: rgba(0, 0, 0, 0.8);
876
+ z-index: 1000;
877
+ justify-content: center;
878
+ align-items: center;
879
+ }
880
+
881
+ .image-modal.active {
882
+ display: flex;
883
+ }
884
+
885
+ .modal-content {
886
+ max-width: 90%;
887
+ max-height: 90%;
888
+ }
889
+
890
+ .close-modal {
891
+ position: absolute;
892
+ top: 20px;
893
+ right: 30px;
894
+ color: white;
895
+ font-size: 30px;
896
+ cursor: pointer;
897
+ }
898
+
899
+ /* Python runs simulation modal boxes */
900
+ .python-modal {
901
+ display: none;
902
+ position: fixed;
903
+ top: 0;
904
+ left: 0;
905
+ width: 100%;
906
+ height: 100%;
907
+ background-color: rgba(0, 0, 0, 0.8);
908
+ z-index: 1000;
909
+ justify-content: center;
910
+ align-items: center;
911
+ }
912
+
913
+ .python-modal.active {
914
+ display: flex;
915
+ }
916
+
917
+ .python-console {
918
+ width: 80%;
919
+ height: 80%;
920
+ background-color: #1e1e1e;
921
+ color: #f8f8f8;
922
+ border-radius: 8px;
923
+ padding: 15px;
924
+ font-family: 'Courier New', monospace;
925
+ overflow: auto;
926
+ }
927
+
928
+ .python-output {
929
+ white-space: pre-wrap;
930
+ line-height: 1.5;
931
+ }
932
+
933
+ .step-line {
934
+ flex-grow: 1;
935
+ height: 2px;
936
+ background-color: var(--border-color);
937
+ margin-left: 10px;
938
+ }
939
+
940
+ .step-info {
941
+ margin-left: 15px;
942
+ font-weight: bold;
943
+ color: var(--text-light);
944
+ font-size: 0.9em;
945
+ }
946
+
947
+ .step-item strong {
948
+ display: block;
949
+ margin-bottom: 8px;
950
+ color: #007bff;
951
+ font-size: 0.9em;
952
+ }
953
+
954
+ .step-item div {
955
+ color: #444;
956
+ line-height: 1.6;
957
+ }
958
+
959
+ .title {
960
+ font-size: 7rem;
961
+ margin-bottom: 1rem;
962
+ background: linear-gradient(45deg, #00dc82 0%, #36e4da 50%, #0047e1 100%);
963
+ -webkit-background-clip: text;
964
+ -webkit-text-fill-color: transparent;
965
+ animation: glow 2s ease-in-out infinite alternate;
966
+ letter-spacing: -2px;
967
+ font-weight: 900;
968
+ line-height: 1;
969
+ }
970
+
971
+ @keyframes glow {
972
+ from {
973
+ text-shadow: 0 0 20px rgba(0, 220, 130, 0.6),
974
+ 0 0 40px rgba(54, 228, 218, 0.4),
975
+ 0 0 60px rgba(0, 71, 225, 0.2);
976
+ }
977
+ to {
978
+ text-shadow: 0 0 40px rgba(0, 220, 130, 0.8),
979
+ 0 0 60px rgba(54, 228, 218, 0.6),
980
+ 0 0 80px rgba(0, 71, 225, 0.4);
981
+ }
982
+ }
983
+
984
+ .subtitle {
985
+ font-size: 1.8rem;
986
+ margin-bottom: 1.5rem;
987
+ color: #999;
988
+ font-weight: 500;
989
+ letter-spacing: 0.5px;
990
+ line-height: 1.3;
991
+ }
992
+
993
+ .description {
994
+ font-size: 1.1rem;
995
+ line-height: 1.6;
996
+ margin-bottom: 2.5rem;
997
+ color: #888;
998
+ max-width: 680px;
999
+ margin-left: auto;
1000
+ margin-right: auto;
1001
+ font-weight: 400;
1002
+ letter-spacing: 0.2px;
1003
+ }
1004
+
1005
+ .cta-button {
1006
+ display: inline-block;
1007
+ padding: 0.9rem 2.5rem;
1008
+ font-size: 1rem;
1009
+ color: white;
1010
+ background: linear-gradient(45deg, #00dc82, #36e4da);
1011
+ border: none;
1012
+ border-radius: 25px;
1013
+ cursor: pointer;
1014
+ text-decoration: none;
1015
+ transition: all 0.3s ease;
1016
+ font-weight: 600;
1017
+ letter-spacing: 2px;
1018
+ text-transform: uppercase;
1019
+ }
1020
+
1021
+ .cta-button:hover {
1022
+ transform: translateY(-2px) scale(1.03);
1023
+ box-shadow: 0 6px 15px rgba(0, 220, 130, 0.4);
1024
+ }
1025
+
1026
+ /* 响应式设计 */
1027
+ @media screen and (max-width: 1200px) {
1028
+ .title {
1029
+ font-size: 6rem;
1030
+ }
1031
+
1032
+ .hero-section {
1033
+ padding: 2rem 1.5rem;
1034
+ max-width: 800px;
1035
+ }
1036
+ }
1037
+
1038
+ @media screen and (max-width: 768px) {
1039
+ .title {
1040
+ font-size: 4.5rem;
1041
+ letter-spacing: -1px;
1042
+ }
1043
+
1044
+ .subtitle {
1045
+ font-size: 1.5rem;
1046
+ margin-bottom: 1.2rem;
1047
+ }
1048
+
1049
+ .description {
1050
+ font-size: 1rem;
1051
+ margin-bottom: 2.5rem;
1052
+ padding: 0 1rem;
1053
+ }
1054
+
1055
+ .cta-button {
1056
+ padding: 0.8rem 2.2rem;
1057
+ font-size: 0.95rem;
1058
+ }
1059
+
1060
+ .emoji {
1061
+ font-size: 2rem;
1062
+ }
1063
+ }
1064
+
1065
+ @media screen and (max-width: 480px) {
1066
+ .title {
1067
+ font-size: 3.5rem;
1068
+ margin-bottom: 0.8rem;
1069
+ }
1070
+
1071
+ .subtitle {
1072
+ font-size: 1.3rem;
1073
+ margin-bottom: 1rem;
1074
+ }
1075
+
1076
+ .description {
1077
+ font-size: 0.9rem;
1078
+ line-height: 1.6;
1079
+ margin-bottom: 2rem;
1080
+ }
1081
+
1082
+ .cta-button {
1083
+ padding: 0.7rem 2rem;
1084
+ font-size: 0.9rem;
1085
+ border-radius: 20px;
1086
+ }
1087
+
1088
+ .emoji {
1089
+ font-size: 1.5rem;
1090
+ }
1091
+
1092
+ .hero-section {
1093
+ padding: 1.5rem 1rem;
1094
+ }
1095
+ }
1096
+
1097
+ @media screen and (max-width: 360px) {
1098
+ .title {
1099
+ font-size: 3rem;
1100
+ }
1101
+
1102
+ .subtitle {
1103
+ font-size: 1.1rem;
1104
+ }
1105
+
1106
+ .description {
1107
+ font-size: 0.85rem;
1108
+ }
1109
+
1110
+ .cta-button {
1111
+ padding: 0.6rem 1.8rem;
1112
+ font-size: 0.85rem;
1113
+ }
1114
+ }
1115
+
1116
+ /* 适配高度 */
1117
+ @media screen and (max-height: 700px) {
1118
+ .hero-section {
1119
+ padding: 1rem;
1120
+ }
1121
+
1122
+ .description {
1123
+ margin-bottom: 2rem;
1124
+ }
1125
+ }
1126
+
1127
+ /* 适配横屏模式 */
1128
+ @media screen and (max-height: 500px) and (orientation: landscape) {
1129
+ .hero-section {
1130
+ padding: 1rem;
1131
+ }
1132
+
1133
+ .title {
1134
+ font-size: 3.5rem;
1135
+ margin-bottom: 0.5rem;
1136
+ }
1137
+
1138
+ .subtitle {
1139
+ font-size: 1.2rem;
1140
+ margin-bottom: 0.8rem;
1141
+ }
1142
+
1143
+ .description {
1144
+ font-size: 0.9rem;
1145
+ margin-bottom: 1.5rem;
1146
+ }
1147
+
1148
+ .cta-button {
1149
+ padding: 0.8rem 2.5rem;
1150
+ }
1151
+
1152
+ .emoji {
1153
+ display: none;
1154
+ }
1155
+ }
1156
+
1157
+ /* Homepage styles */
1158
+ .home-container {
1159
+ min-height: 100vh;
1160
+ display: flex;
1161
+ justify-content: center;
1162
+ align-items: center;
1163
+ background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
1164
+ color: white;
1165
+ position: relative;
1166
+ overflow: hidden;
1167
+ }
1168
+
1169
+ .hero-section {
1170
+ text-align: center;
1171
+ padding: 2rem;
1172
+ position: relative;
1173
+ z-index: 1;
1174
+ max-width: 1000px;
1175
+ margin: 0 auto;
1176
+ }
1177
+
1178
+ .floating-emojis {
1179
+ position: absolute;
1180
+ top: 0;
1181
+ left: 0;
1182
+ width: 100%;
1183
+ height: 100%;
1184
+ pointer-events: none;
1185
+ }
1186
+
1187
+ .emoji {
1188
+ position: absolute;
1189
+ font-size: 2.5rem;
1190
+ opacity: 0;
1191
+ animation: float 10s ease-in-out infinite;
1192
+ animation-delay: var(--delay);
1193
+ filter: drop-shadow(0 0 10px rgba(0, 220, 130, 0.3));
1194
+ }
1195
+
1196
+ .emoji:nth-child(1) { top: 20%; left: 20%; }
1197
+ .emoji:nth-child(2) { top: 30%; left: 80%; }
1198
+ .emoji:nth-child(3) { top: 70%; left: 30%; }
1199
+ .emoji:nth-child(4) { top: 60%; left: 70%; }
1200
+ .emoji:nth-child(5) { top: 40%; left: 50%; }
1201
+
1202
+ @keyframes float {
1203
+ 0% {
1204
+ transform: translateY(0) rotate(0);
1205
+ opacity: 0;
1206
+ }
1207
+ 20% {
1208
+ opacity: 1;
1209
+ }
1210
+ 80% {
1211
+ opacity: 1;
1212
+ }
1213
+ 100% {
1214
+ transform: translateY(-100vh) rotate(360deg);
1215
+ opacity: 0;
1216
+ }
1217
+ }
1218
+
1219
+ .step-info-container {
1220
+ margin-bottom: 10px;
1221
+ }
1222
+
1223
+ .step-info-box {
1224
+ background: linear-gradient(90deg, rgba(28, 30, 44, 0.9), rgba(36, 38, 52, 0.9));
1225
+ border: 1px solid rgba(60, 80, 220, 0.2);
1226
+ padding: 10px 15px;
1227
+ margin-top: 8px;
1228
+ border-radius: 8px;
1229
+ display: flex;
1230
+ align-items: center;
1231
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
1232
+ position: relative;
1233
+ overflow: hidden;
1234
+ }
1235
+
1236
+ .step-info-box::before {
1237
+ content: '';
1238
+ position: absolute;
1239
+ top: 0;
1240
+ left: 0;
1241
+ width: 100%;
1242
+ height: 2px;
1243
+ background: linear-gradient(90deg,
1244
+ rgba(60, 80, 220, 0.1),
1245
+ rgba(60, 80, 220, 0.3),
1246
+ rgba(120, 120, 220, 0.6),
1247
+ rgba(60, 80, 220, 0.3),
1248
+ rgba(60, 80, 220, 0.1)
1249
+ );
1250
+ }
1251
+
1252
+ .current-step {
1253
+ background-color: #f0f5ff;
1254
+ border: 1px solid #e0e0e0;
1255
+ border-left: 3px solid #4285f4;
1256
+ padding: 8px 12px;
1257
+ margin-top: 8px;
1258
+ border-radius: 4px;
1259
+ display: flex;
1260
+ align-items: center;
1261
+ }
1262
+
1263
+ .emoji-icon {
1264
+ margin-right: 14px;
1265
+ font-size: 18px;
1266
+ display: inline-flex;
1267
+ width: 36px;
1268
+ height: 36px;
1269
+ justify-content: center;
1270
+ align-items: center;
1271
+ background: linear-gradient(135deg, rgba(45, 49, 66, 0.8), rgba(28, 31, 40, 0.8));
1272
+ border-radius: 50%;
1273
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2), inset 0 0 15px rgba(60, 80, 220, 0.3);
1274
+ position: relative;
1275
+ z-index: 2;
1276
+ border: 1px solid rgba(60, 80, 220, 0.15);
1277
+ color: rgba(255, 255, 255, 0.9);
1278
+ }
1279
+
1280
+ .emoji-icon::before {
1281
+ content: '';
1282
+ position: absolute;
1283
+ width: 100%;
1284
+ height: 100%;
1285
+ border-radius: 50%;
1286
+ background: radial-gradient(circle at 30% 30%, rgba(60, 80, 220, 0.25), transparent 60%);
1287
+ z-index: -1;
1288
+ }
1289
+
1290
+ .step-highlight {
1291
+ background-color: #ffefef; /* 红色背景 */
1292
+ border: 1px solid #ffcdd2;
1293
+ border-left: 3px solid #f44336;
1294
+ padding: 8px 12px;
1295
+ margin-top: 8px;
1296
+ border-radius: 4px;
1297
+ display: flex;
1298
+ align-items: center;
1299
+ }
1300
+
1301
+ .content-highlight {
1302
+ background-color: #e3f2fd; /* 蓝色背景 */
1303
+ border: 1px solid #bbdefb;
1304
+ border-left: 3px solid #2196f3;
1305
+ padding: 10px;
1306
+ margin-bottom: 10px;
1307
+ border-radius: 4px;
1308
+ overflow-x: auto;
1309
+ }
1310
+
1311
+ .content-highlight pre {
1312
+ margin: 0;
1313
+ white-space: pre-wrap;
1314
+ word-break: break-word;
1315
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
1316
+ font-size: 14px;
1317
+ line-height: 1.5;
1318
+ }
1319
+
1320
+ /* New top navigation bar design */
1321
+ .header {
1322
+ position: fixed;
1323
+ top: 0;
1324
+ left: 0;
1325
+ right: 0;
1326
+ height: 56px;
1327
+ background-color: #fff;
1328
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
1329
+ display: flex;
1330
+ align-items: center;
1331
+ justify-content: space-between;
1332
+ padding: 0 20px;
1333
+ z-index: 100;
1334
+ transition: all 0.3s ease;
1335
+ }
1336
+
1337
+ .header-left, .header-center, .header-right {
1338
+ display: flex;
1339
+ align-items: center;
1340
+ gap: 16px;
1341
+ }
1342
+
1343
+ .header-left {
1344
+ flex: 1;
1345
+ }
1346
+
1347
+ .logo {
1348
+ display: flex;
1349
+ align-items: center;
1350
+ gap: 10px;
1351
+ }
1352
+
1353
+ /* 移除链接下划线的高优先级规则 */
1354
+ .header a.logo,
1355
+ .header-left a.logo,
1356
+ .header a,
1357
+ a.logo {
1358
+ text-decoration: none !important;
1359
+ border-bottom: none !important;
1360
+ }
1361
+
1362
+ .header a.logo:hover,
1363
+ .header-left a.logo:hover,
1364
+ .header a:hover,
1365
+ a.logo:hover,
1366
+ .header a.logo:focus,
1367
+ .header-left a.logo:focus,
1368
+ .header a:focus,
1369
+ a.logo:focus,
1370
+ .header a.logo:active,
1371
+ .header-left a.logo:active,
1372
+ .header a:active,
1373
+ a.logo:active {
1374
+ text-decoration: none !important;
1375
+ border-bottom: none !important;
1376
+ }
1377
+
1378
+ /* 优化OpenManus文字渐变效果 */
1379
+ .header .logo-text,
1380
+ .header-left .logo-text,
1381
+ span.logo-text,
1382
+ .logo-text {
1383
+ font-size: 24px;
1384
+ font-weight: 700;
1385
+ background: linear-gradient(135deg, #0575E6 0%, #0096FF 35%, #00B4FF 65%, #00D2FF 100%);
1386
+ -webkit-background-clip: text;
1387
+ background-clip: text;
1388
+ -webkit-text-fill-color: transparent;
1389
+ text-decoration: none !important;
1390
+ border-bottom: none !important;
1391
+ display: inline-block;
1392
+ letter-spacing: -0.5px;
1393
+ text-shadow: 0 0 8px rgba(5, 117, 230, 0.2);
1394
+ transition: all 0.3s ease;
1395
+ white-space: nowrap;
1396
+ }
1397
+
1398
+ .header .logo-text:hover,
1399
+ .header-left .logo-text:hover,
1400
+ span.logo-text:hover,
1401
+ .logo-text:hover {
1402
+ transform: scale(1.05);
1403
+ text-shadow: 0 0 15px rgba(5, 117, 230, 0.4);
1404
+ text-decoration: none !important;
1405
+ border-bottom: none !important;
1406
+ }
1407
+
1408
+ /* History button style reset - no visual effects */
1409
+ .history-toggle {
1410
+ all: unset; /* Reset all CSS properties */
1411
+ cursor: pointer; /* Only keep hand cursor */
1412
+ color: #777;
1413
+ position: relative;
1414
+ margin: 0 15px 0 0;
1415
+ padding: 0;
1416
+ font-size: inherit;
1417
+ line-height: normal;
1418
+ display: inline-block;
1419
+ }
1420
+
1421
+ /* Ensure icon style is simple */
1422
+ .history-toggle i {
1423
+ font-size: 18px;
1424
+ }
1425
+
1426
+ /* History count indicator - essential styles */
1427
+ .history-count {
1428
+ position: absolute;
1429
+ top: -5px;
1430
+ right: -5px;
1431
+ background-color: #555;
1432
+ color: white;
1433
+ min-width: 14px;
1434
+ height: 14px;
1435
+ border-radius: 7px;
1436
+ font-size: 9px;
1437
+ font-weight: 600;
1438
+ text-align: center;
1439
+ line-height: 14px;
1440
+ padding: 0 3px;
1441
+ }
1442
+
1443
+ /* Side history panel */
1444
+ .history-panel {
1445
+ position: fixed;
1446
+ left: 0;
1447
+ top: 56px;
1448
+ width: 280px;
1449
+ height: calc(100vh - 56px);
1450
+ background-color: white;
1451
+ box-shadow: 3px 0 10px rgba(0, 0, 0, 0.05);
1452
+ z-index: 99;
1453
+ transform: translateX(-100%);
1454
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1455
+ overflow: hidden;
1456
+ display: flex;
1457
+ flex-direction: column;
1458
+ }
1459
+
1460
+ .history-panel.show {
1461
+ transform: translateX(0);
1462
+ }
1463
+
1464
+ .history-header {
1465
+ display: flex;
1466
+ align-items: center;
1467
+ justify-content: space-between;
1468
+ padding: 15px 20px;
1469
+ border-bottom: 1px solid #eee;
1470
+ }
1471
+
1472
+ .history-title {
1473
+ font-size: 16px;
1474
+ font-weight: 600;
1475
+ color: #333;
1476
+ }
1477
+
1478
+ .history-actions {
1479
+ display: flex;
1480
+ gap: 10px;
1481
+ }
1482
+
1483
+ .history-action-btn {
1484
+ background: transparent;
1485
+ border: none;
1486
+ color: #666;
1487
+ cursor: pointer;
1488
+ padding: 5px;
1489
+ border-radius: 4px;
1490
+ transition: all 0.2s;
1491
+ }
1492
+
1493
+ .history-action-btn:hover {
1494
+ background-color: rgba(0, 0, 0, 0.05);
1495
+ color: #0575E6;
1496
+ transform: none;
1497
+ box-shadow: none;
1498
+ }
1499
+
1500
+ .task-list {
1501
+ flex: 1;
1502
+ overflow-y: auto;
1503
+ padding: 10px 15px;
1504
+ }
1505
+
1506
+ .task-card {
1507
+ background: #fff;
1508
+ padding: 12px 15px;
1509
+ margin-bottom: 10px;
1510
+ border-radius: 8px;
1511
+ cursor: pointer;
1512
+ border: 1px solid #eee;
1513
+ transition: all 0.2s;
1514
+ }
1515
+
1516
+ .task-card:hover {
1517
+ transform: translateY(-2px);
1518
+ box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
1519
+ border-color: #ddd;
1520
+ }
1521
+
1522
+ .task-card.active {
1523
+ border-left: 3px solid #0e68f1;
1524
+ background-color: rgba(14, 104, 241, 0.05);
1525
+ }
1526
+
1527
+ .task-title {
1528
+ font-weight: 500;
1529
+ margin-bottom: 5px;
1530
+ color: #333;
1531
+ overflow: hidden;
1532
+ text-overflow: ellipsis;
1533
+ white-space: nowrap;
1534
+ }
1535
+
1536
+ .task-meta {
1537
+ display: flex;
1538
+ justify-content: space-between;
1539
+ font-size: 12px;
1540
+ color: #888;
1541
+ }
1542
+
1543
+ /* Overlay */
1544
+ .overlay {
1545
+ position: fixed;
1546
+ top: 0;
1547
+ left: 0;
1548
+ width: 100vw;
1549
+ height: 100vh;
1550
+ background-color: rgba(0, 0, 0, 0.3);
1551
+ z-index: 98;
1552
+ opacity: 0;
1553
+ pointer-events: none;
1554
+ transition: opacity 0.3s ease;
1555
+ }
1556
+
1557
+ .overlay.show {
1558
+ opacity: 1;
1559
+ pointer-events: all;
1560
+ }
1561
+
1562
+ /* Container adjustment, reserve space for history panel */
1563
+ .container.with-history {
1564
+ padding-left: 280px;
1565
+ transition: padding 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1566
+ }
1567
+
1568
+ /* Welcome title style optimization */
1569
+ .welcome-title {
1570
+ font-size: 3.8rem;
1571
+ margin-bottom: 18px;
1572
+ color: #333;
1573
+ font-weight: 700;
1574
+ line-height: 1.2;
1575
+ letter-spacing: -0.5px;
1576
+ }
1577
+
1578
+ /* Welcome page subtitle style optimization */
1579
+ .welcome-message p {
1580
+ font-size: 1.1rem;
1581
+ color: #555;
1582
+ margin-bottom: 10px;
1583
+ background: linear-gradient(135deg, #0575E6 0%, #0096FF 35%, #00B4FF 65%, #00D2FF 100%);
1584
+ -webkit-background-clip: text;
1585
+ background-clip: text;
1586
+ -webkit-text-fill-color: transparent;
1587
+ font-weight: 600;
1588
+ animation: fadeIn 0.8s ease-in-out;
1589
+ animation-delay: 0.2s;
1590
+ animation-fill-mode: both;
1591
+ }
1592
+
1593
+ /* Restore login icon style */
1594
+ .login-btn i {
1595
+ font-size: 14px;
1596
+ }
1597
+
1598
+ /* Remove any possible overrides for new styles */
1599
+ button {
1600
+ border: none;
1601
+ cursor: pointer;
1602
+ transition: all 0.3s ease;
1603
+ }
1604
+
1605
+ .input-container {
1606
+ width: 100%;
1607
+ background-color: white;
1608
+ border-radius: 12px;
1609
+ padding: 15px 20px;
1610
+ box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08);
1611
+ display: flex;
1612
+ gap: 15px;
1613
+ margin-top: auto;
1614
+ }
1615
+
1616
+ #prompt-input {
1617
+ flex: 1;
1618
+ padding: 14px 20px;
1619
+ border: 1px solid #e0e0e0;
1620
+ border-radius: 24px;
1621
+ font-size: 1rem;
1622
+ transition: all 0.3s ease;
1623
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
1624
+ }
1625
+
1626
+ #prompt-input:focus {
1627
+ border-color: #0096FF;
1628
+ box-shadow: 0 2px 12px rgba(0, 150, 255, 0.15);
1629
+ outline: none;
1630
+ }
static/themes/openmanus/templates/chat.html ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>OpenManus</title>
7
+ <link rel="stylesheet" href="/static/themes/openmanus/static/style.css">
8
+ <!-- Add Font Awesome icon library -->
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ </head>
11
+ <body>
12
+ <!-- Top navigation bar -->
13
+ <header class="header">
14
+ <div class="header-left">
15
+ <a href="/" class="logo">
16
+ <span class="logo-text">OpenManus</span>
17
+ </a>
18
+ </div>
19
+ <div class="header-right">
20
+ <!-- History icon button - using CSS class -->
21
+ <button class="history-toggle">
22
+ <i class="fas fa-history"></i>
23
+ <span class="history-count">0</span>
24
+ </button>
25
+ <a href="#" class="login-btn">
26
+ <i class="fas fa-user"></i>
27
+ Login
28
+ </a>
29
+ </div>
30
+ </header>
31
+
32
+ <!-- History panel -->
33
+ <aside class="history-panel">
34
+ <div class="history-header">
35
+ <div class="history-title">History</div>
36
+ <div class="history-actions">
37
+ <button class="history-action-btn" title="Refresh" onclick="loadHistory()">
38
+ <i class="fas fa-sync-alt"></i>
39
+ </button>
40
+ </div>
41
+ </div>
42
+ <div id="task-list" class="task-list">
43
+ <!-- Task list will be dynamically loaded through JavaScript -->
44
+ </div>
45
+ </aside>
46
+
47
+ <!-- Background overlay -->
48
+ <div class="overlay"></div>
49
+
50
+ <!-- Main container -->
51
+ <div class="container">
52
+ <div class="main-panel">
53
+ <div id="task-container" class="task-container">
54
+ <div class="welcome-message">
55
+ <!-- Add large logo animation -->
56
+ <div class="logo-animation">
57
+ <img src="/static/themes/openmanus/static/logo.png" alt="OpenManus Logo" class="welcome-logo">
58
+ </div>
59
+
60
+ <p class="highlight-text">Your autonomous intelligent assistant</p>
61
+ <div class="animated-subtext">Ready to help with anything, anytime</div>
62
+ </div>
63
+ <div id="steps-container" class="steps-container"></div>
64
+ </div>
65
+
66
+ <div id="result-panel" class="result-panel hidden">
67
+ <div class="result-header">
68
+ <h2>Manus Computer</h2>
69
+ <div class="result-controls">
70
+ <div class="minimize-result" onclick="toggleResultPanel()"></div>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="step-info-container">
75
+ <div id="current-step" class="step-info-box">
76
+ <!-- Step information will be dynamically populated by JavaScript -->
77
+ </div>
78
+ </div>
79
+
80
+ <div id="result-container" class="result-container"></div>
81
+ </div>
82
+
83
+ <div class="input-container">
84
+ <input type="text" id="prompt-input" placeholder="Type your question here...">
85
+ <button onclick="createTask()" class="send-btn">Send</button>
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ <script src="/static/themes/openmanus/static/main.js"></script>
91
+ </body>
92
+ </html>
static/themes/openmanus/theme.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "name": "Manus",
3
+ "description": "OpenManus的默认界面主题",
4
+ "author": "Ray",
5
+ "version": "1.0.0"
6
+ }