hyper-scheduler 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/devtools-4xVHTaUz.js +2161 -0
  2. package/dist/devtools-DdQ1I25H.cjs +1 -0
  3. package/dist/index.cjs +1 -0
  4. package/dist/index.js +995 -0
  5. package/dist/index.umd.cjs +1 -0
  6. package/package.json +7 -1
  7. package/.editorconfig +0 -21
  8. package/.eslintrc.cjs +0 -26
  9. package/GEMINI.md +0 -1
  10. package/docs/.vitepress/config.ts +0 -52
  11. package/docs/README.md +0 -120
  12. package/docs/api/devtools.md +0 -232
  13. package/docs/api/index.md +0 -178
  14. package/docs/api/scheduler.md +0 -322
  15. package/docs/api/task.md +0 -439
  16. package/docs/api/types.md +0 -365
  17. package/docs/examples/index.md +0 -295
  18. package/docs/guide/best-practices.md +0 -436
  19. package/docs/guide/core-concepts.md +0 -363
  20. package/docs/guide/getting-started.md +0 -138
  21. package/docs/index.md +0 -33
  22. package/docs/public/logo.svg +0 -54
  23. package/examples/browser/index.html +0 -354
  24. package/examples/node/simple.js +0 -36
  25. package/examples/react-demo/index.html +0 -12
  26. package/examples/react-demo/package.json +0 -23
  27. package/examples/react-demo/src/App.css +0 -212
  28. package/examples/react-demo/src/App.jsx +0 -160
  29. package/examples/react-demo/src/main.jsx +0 -9
  30. package/examples/react-demo/vite.config.ts +0 -12
  31. package/examples/react-demo/yarn.lock +0 -752
  32. package/examples/vue-demo/index.html +0 -12
  33. package/examples/vue-demo/package.json +0 -21
  34. package/examples/vue-demo/src/App.vue +0 -373
  35. package/examples/vue-demo/src/main.ts +0 -4
  36. package/examples/vue-demo/vite.config.ts +0 -13
  37. package/examples/vue-demo/yarn.lock +0 -375
  38. package/src/constants.ts +0 -18
  39. package/src/core/retry-strategy.ts +0 -28
  40. package/src/core/scheduler.ts +0 -601
  41. package/src/core/task-registry.ts +0 -58
  42. package/src/index.ts +0 -74
  43. package/src/platform/browser/browser-timer.ts +0 -66
  44. package/src/platform/browser/main-thread-timer.ts +0 -16
  45. package/src/platform/browser/worker.ts +0 -31
  46. package/src/platform/node/debug-cli.ts +0 -19
  47. package/src/platform/node/node-timer.ts +0 -15
  48. package/src/platform/timer-strategy.ts +0 -19
  49. package/src/plugins/dev-tools.ts +0 -101
  50. package/src/types.ts +0 -115
  51. package/src/ui/components/devtools.ts +0 -525
  52. package/src/ui/components/floating-trigger.ts +0 -102
  53. package/src/ui/components/icons.ts +0 -16
  54. package/src/ui/components/resizer.ts +0 -129
  55. package/src/ui/components/task-detail.ts +0 -228
  56. package/src/ui/components/task-header.ts +0 -319
  57. package/src/ui/components/task-list.ts +0 -416
  58. package/src/ui/components/timeline.ts +0 -364
  59. package/src/ui/debug-panel.ts +0 -56
  60. package/src/ui/i18n/en.ts +0 -76
  61. package/src/ui/i18n/index.ts +0 -42
  62. package/src/ui/i18n/zh.ts +0 -76
  63. package/src/ui/store/dev-tools-store.ts +0 -191
  64. package/src/ui/styles/theme.css.ts +0 -56
  65. package/src/ui/styles.ts +0 -43
  66. package/src/utils/cron-lite.ts +0 -221
  67. package/src/utils/cron.ts +0 -20
  68. package/src/utils/id.ts +0 -10
  69. package/src/utils/schedule.ts +0 -93
  70. package/src/vite-env.d.ts +0 -1
  71. package/stats.html +0 -4949
  72. package/tests/integration/Debug.test.ts +0 -58
  73. package/tests/unit/Plugin.test.ts +0 -16
  74. package/tests/unit/RetryStrategy.test.ts +0 -21
  75. package/tests/unit/Scheduler.test.ts +0 -38
  76. package/tests/unit/schedule.test.ts +0 -70
  77. package/tests/unit/ui/DevToolsStore.test.ts +0 -67
  78. package/tsconfig.json +0 -28
  79. package/vite.config.ts +0 -51
  80. package/vitest.config.ts +0 -24
@@ -1,354 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Hyper Scheduler - 浏览器示例</title>
8
- <style>
9
- :root {
10
- --bg-color: #f8fafc;
11
- --card-bg: #ffffff;
12
- --text-primary: #1e293b;
13
- --text-secondary: #64748b;
14
- --accent-color: #3b82f6;
15
- --accent-hover: #2563eb;
16
- --danger-color: #ef4444;
17
- --danger-hover: #dc2626;
18
- --success-color: #10b981;
19
- --border-radius: 12px;
20
- --shadow-sm: 0 1px 3px rgba(0,0,0,0.1);
21
- --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06);
22
- --font-mono: 'SFMono-Regular', Consolas, 'Lxgw WenKai', 'Liberation Mono', Menlo, monospace;
23
- }
24
-
25
- * {
26
- margin: 0;
27
- padding: 0;
28
- box-sizing: border-box;
29
- }
30
-
31
- body {
32
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
33
- background: var(--bg-color);
34
- color: var(--text-primary);
35
- height: 100vh;
36
- display: flex;
37
- align-items: center;
38
- justify-content: center;
39
- padding: 20px;
40
- }
41
-
42
- .dashboard {
43
- display: grid;
44
- grid-template-columns: 300px 1fr;
45
- gap: 24px;
46
- width: 100%;
47
- max-width: 1000px;
48
- height: 600px;
49
- background: var(--bg-color);
50
- }
51
-
52
- /* 左侧控制面板 */
53
- .control-panel {
54
- background: var(--card-bg);
55
- border-radius: var(--border-radius);
56
- padding: 24px;
57
- box-shadow: var(--shadow-md);
58
- display: flex;
59
- flex-direction: column;
60
- justify-content: space-between;
61
- }
62
-
63
- .header h1 {
64
- font-size: 24px;
65
- font-weight: 700;
66
- margin-bottom: 8px;
67
- background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
68
- -webkit-background-clip: text;
69
- -webkit-text-fill-color: transparent;
70
- }
71
-
72
- .header p {
73
- color: var(--text-secondary);
74
- font-size: 14px;
75
- margin-bottom: 24px;
76
- }
77
-
78
- .task-status {
79
- margin-bottom: auto;
80
- }
81
-
82
- .status-item {
83
- display: flex;
84
- align-items: center;
85
- padding: 12px;
86
- background: #f1f5f9;
87
- border-radius: 8px;
88
- margin-bottom: 12px;
89
- font-size: 14px;
90
- }
91
-
92
- .status-dot {
93
- width: 8px;
94
- height: 8px;
95
- border-radius: 50%;
96
- margin-right: 10px;
97
- }
98
-
99
- .dot-main { background: #ef4444; box-shadow: 0 0 8px rgba(239, 68, 68, 0.4); }
100
- .dot-worker { background: #3b82f6; box-shadow: 0 0 8px rgba(59, 130, 246, 0.4); }
101
-
102
- .actions {
103
- display: flex;
104
- flex-direction: column;
105
- gap: 12px;
106
- }
107
-
108
- /* 按钮状态控制 */
109
- #btn-stop { display: none; }
110
- body.running #btn-start { display: none; }
111
- body.running #btn-stop { display: block; }
112
-
113
- button {
114
- display: flex;
115
- align-items: center;
116
- justify-content: center;
117
- width: 100%;
118
- padding: 12px;
119
- border: none;
120
- border-radius: 8px;
121
- font-size: 14px;
122
- font-weight: 600;
123
- cursor: pointer;
124
- transition: all 0.2s ease;
125
- }
126
-
127
- .btn-start {
128
- background: var(--accent-color);
129
- color: white;
130
- }
131
- .btn-start:hover { background: var(--accent-hover); transform: translateY(-1px); }
132
- .btn-start:active { transform: translateY(0); }
133
-
134
- .btn-stop {
135
- background: #fff;
136
- color: var(--danger-color);
137
- border: 1px solid var(--danger-color);
138
- }
139
- .btn-stop:hover { background: #fef2f2; }
140
-
141
- .info-tip {
142
- margin-top: 20px;
143
- font-size: 12px;
144
- color: var(--text-secondary);
145
- text-align: center;
146
- background: #f8fafc;
147
- padding: 8px;
148
- border-radius: 6px;
149
- border: 1px dashed #cbd5e1;
150
- }
151
-
152
- /* 右侧日志面板 */
153
- .log-panel {
154
- background: #1e293b; /* 深色背景用于日志 */
155
- border-radius: var(--border-radius);
156
- box-shadow: var(--shadow-md);
157
- display: flex;
158
- flex-direction: column;
159
- overflow: hidden;
160
- }
161
-
162
- .log-header {
163
- padding: 16px 24px;
164
- border-bottom: 1px solid #334155;
165
- display: flex;
166
- justify-content: space-between;
167
- align-items: center;
168
- background: #0f172a;
169
- }
170
-
171
- .log-header h2 {
172
- color: #e2e8f0;
173
- font-size: 16px;
174
- font-weight: 600;
175
- display: flex;
176
- align-items: center;
177
- gap: 8px;
178
- }
179
-
180
- .log-box {
181
- flex: 1;
182
- padding: 20px;
183
- overflow-y: auto;
184
- font-family: var(--font-mono);
185
- font-size: 13px;
186
- line-height: 1.8;
187
- }
188
-
189
- /* 滚动条美化 */
190
- .log-box::-webkit-scrollbar { width: 6px; }
191
- .log-box::-webkit-scrollbar-track { background: #1e293b; }
192
- .log-box::-webkit-scrollbar-thumb { background: #475569; border-radius: 3px; }
193
-
194
- /* 日志条目样式 */
195
- .log-item {
196
- display: flex;
197
- margin-bottom: 6px;
198
- animation: fadeIn 0.3s ease;
199
- }
200
-
201
- @keyframes fadeIn {
202
- from { opacity: 0; transform: translateY(5px); }
203
- to { opacity: 1; transform: translateY(0); }
204
- }
205
-
206
- .log-time {
207
- color: #64748b;
208
- margin-right: 12px;
209
- min-width: 85px;
210
- }
211
-
212
- .log-content { color: #e2e8f0; }
213
- .log-type-success .log-content { color: #4ade80; }
214
- .log-type-info .log-content { color: #60a5fa; }
215
- .log-type-error .log-content { color: #f87171; }
216
-
217
- @media (max-width: 768px) {
218
- .dashboard { grid-template-columns: 1fr; height: auto; }
219
- body { height: auto; }
220
- .log-panel { height: 400px; }
221
- }
222
- </style>
223
- </head>
224
-
225
- <body>
226
- <div class="dashboard">
227
- <!-- 左侧控制区 -->
228
- <div class="control-panel">
229
- <div>
230
- <div class="header">
231
- <h1>Hyper Scheduler</h1>
232
- <p>双线程任务调度演示</p>
233
- </div>
234
-
235
- <div class="task-status">
236
- <div class="status-item">
237
- <span class="status-dot dot-main"></span>
238
- <div>
239
- <strong>主线程任务</strong>
240
- <div style="font-size: 12px; color: #64748b; margin-top: 2px">每 3 秒 (driver: 'main')</div>
241
- </div>
242
- </div>
243
- <div class="status-item">
244
- <span class="status-dot dot-worker"></span>
245
- <div>
246
- <strong>Worker 任务</strong>
247
- <div style="font-size: 12px; color: #64748b; margin-top: 2px">每 5 秒 (driver: 'worker')</div>
248
- </div>
249
- </div>
250
- </div>
251
- </div>
252
-
253
- <div>
254
- <div class="actions">
255
- <button class="btn-start" id="btn-start">
256
- <span style="margin-right: 8px">▶</span> 启动调度器
257
- </button>
258
- <button class="btn-stop" id="btn-stop">
259
- <span style="margin-right: 8px">⏹</span> 停止调度器
260
- </button>
261
- </div>
262
- <div class="info-tip">
263
- 💡 点击右下角悬浮球打开调试面板
264
- </div>
265
- </div>
266
- </div>
267
-
268
- <!-- 右侧日志区 -->
269
- <div class="log-panel">
270
- <div class="log-header">
271
- <h2>
272
- <span>📋</span> 执行日志
273
- </h2>
274
- <div style="font-size: 12px; color: #64748b">实时监控中...</div>
275
- </div>
276
- <div id="logs" class="log-box"></div>
277
- </div>
278
- </div>
279
-
280
- <script src="../../dist/index.umd.cjs"></script>
281
- <script>
282
- const logBox = document.getElementById('logs');
283
-
284
- function log(msg, type = 'info') {
285
- const time = new Date().toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
286
-
287
- const item = document.createElement('div');
288
- item.className = `log-item log-type-${type}`;
289
-
290
- item.innerHTML = `
291
- <span class="log-time">${time}</span>
292
- <span class="log-content">${msg}</span>
293
- `;
294
-
295
- logBox.appendChild(item);
296
-
297
- // 保持最新的日志可见,但如果用户向上滚动了则不强制滚动
298
- const isScrolledToBottom = logBox.scrollHeight - logBox.clientHeight <= logBox.scrollTop + 10;
299
- if (isScrolledToBottom || logBox.children.length <= 2) {
300
- logBox.scrollTop = logBox.scrollHeight;
301
- }
302
- }
303
-
304
- const { Scheduler, DevTools } = window.HyperScheduler;
305
-
306
- const scheduler = new Scheduler({
307
- debug: true,
308
- plugins: [new DevTools({
309
- theme: 'auto',
310
- language: 'zh',
311
- trigger: {
312
- position: 'bottom-right',
313
- backgroundColor: '#3b82f6'
314
- }
315
- })]
316
- });
317
-
318
- // 主线程心跳 (明确指定 driver: 'main')
319
- scheduler.createTask({
320
- id: 'main-heartbeat',
321
- schedule: '3s',
322
- options: { driver: 'main' },
323
- handler: () => {
324
- log('❤️ [Main] 主线程心跳检测正常', 'error'); // 使用 error 样式红色,对应 UI 的红色点
325
- }
326
- });
327
-
328
- // Worker 线程心跳 (默认即为 Worker 驱动)
329
- scheduler.createTask({
330
- id: 'worker-heartbeat',
331
- schedule: '5s',
332
- handler: () => {
333
- log('💙 [Worker] 后台线程任务执行中', 'info'); // 使用 info 样式蓝色,对应 UI 的蓝色点
334
- }
335
- });
336
-
337
- // 按钮事件
338
- document.getElementById('btn-start').onclick = () => {
339
- scheduler.start();
340
- document.body.classList.add('running');
341
- log('🚀 调度器系统已启动', 'success');
342
- };
343
-
344
- document.getElementById('btn-stop').onclick = () => {
345
- scheduler.stop();
346
- document.body.classList.remove('running');
347
- log('⏹️ 调度器系统已停止', 'info');
348
- };
349
-
350
- log('✨ 系统就绪,等待启动指令...', 'info');
351
- </script>
352
- </body>
353
-
354
- </html>
@@ -1,36 +0,0 @@
1
- // 注意: 在实际项目中,你应该使用 import { Scheduler } from 'hyper-scheduler';
2
- // 此处为了演示本地构建版本,直接引用 dist 目录下的 ESM 构建产物
3
-
4
- import { Scheduler } from '../../dist/index.js';
5
-
6
- // 创建调度器
7
- const scheduler = new Scheduler({ debug: true });
8
-
9
- // 辅助函数:格式化时间
10
- const time = () => new Date().toLocaleTimeString('zh-CN', { hour12: false });
11
-
12
- console.log('✨ 系统就绪,等待启动指令...');
13
-
14
- // 主线程心跳 (明确指定 driver: 'main')
15
- scheduler.createTask({
16
- id: 'main-heartbeat',
17
- schedule: '3s',
18
- options: { driver: 'main' }, // 明确指定为主线程驱动
19
- handler: () => {
20
- console.log(`[${time()}] ❤️ [Main] 主线程心跳检测正常`);
21
- }
22
- });
23
-
24
- // Worker 线程心跳 (默认即为 Worker 驱动)
25
- scheduler.createTask({
26
- id: 'worker-heartbeat',
27
- schedule: '5s',
28
- handler: () => {
29
- console.log(`[${time()}] 💙 [Worker] 后台线程任务执行中`);
30
- }
31
- });
32
-
33
- // 启动调度器
34
- scheduler.start();
35
-
36
- console.log(`[${time()}] 🚀 调度器已启动,按 Ctrl+C 退出`);
@@ -1,12 +0,0 @@
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>Hyper Scheduler React Demo</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/src/main.jsx"></script>
11
- </body>
12
- </html>
@@ -1,23 +0,0 @@
1
- {
2
- "name": "react-demo",
3
- "private": true,
4
- "version": "0.0.0",
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "tsc && vite build",
9
- "preview": "vite preview"
10
- },
11
- "dependencies": {
12
- "react": "^18.2.0",
13
- "react-dom": "^18.2.0",
14
- "hyper-scheduler": "file:../../"
15
- },
16
- "devDependencies": {
17
- "@types/react": "^18.2.0",
18
- "@types/react-dom": "^18.2.0",
19
- "@vitejs/plugin-react": "^4.0.0",
20
- "typescript": "^5.2.0",
21
- "vite": "^5.0.0"
22
- }
23
- }
@@ -1,212 +0,0 @@
1
- :root {
2
- --bg-color: #f8fafc;
3
- --card-bg: #ffffff;
4
- --text-primary: #1e293b;
5
- --text-secondary: #64748b;
6
- --accent-color: #3b82f6;
7
- --accent-hover: #2563eb;
8
- --danger-color: #ef4444;
9
- --danger-hover: #dc2626;
10
- --success-color: #10b981;
11
- --border-radius: 12px;
12
- --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -1px rgba(0,0,0,0.06);
13
- --font-mono: 'SFMono-Regular', Consolas, 'Lxgw WenKai', 'Liberation Mono', Menlo, monospace;
14
- }
15
-
16
- * {
17
- margin: 0;
18
- padding: 0;
19
- box-sizing: border-box;
20
- }
21
-
22
- body {
23
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
24
- background: var(--bg-color);
25
- color: var(--text-primary);
26
- min-height: 100vh;
27
- display: flex;
28
- align-items: center;
29
- justify-content: center;
30
- padding: 20px;
31
- }
32
-
33
- .dashboard {
34
- display: grid;
35
- grid-template-columns: 300px 1fr;
36
- gap: 24px;
37
- width: 1000px;
38
- height: 600px;
39
- background: var(--bg-color);
40
- }
41
-
42
- /* 左侧控制面板 */
43
- .control-panel {
44
- background: var(--card-bg);
45
- border-radius: var(--border-radius);
46
- padding: 24px;
47
- box-shadow: var(--shadow-md);
48
- display: flex;
49
- flex-direction: column;
50
- justify-content: space-between;
51
- }
52
-
53
- .header h1 {
54
- font-size: 24px;
55
- font-weight: 700;
56
- margin-bottom: 8px;
57
- background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
58
- -webkit-background-clip: text;
59
- -webkit-text-fill-color: transparent;
60
- }
61
-
62
- .header p {
63
- color: var(--text-secondary);
64
- font-size: 14px;
65
- margin-bottom: 24px;
66
- }
67
-
68
- .task-status {
69
- margin-bottom: auto;
70
- }
71
-
72
- .status-item {
73
- display: flex;
74
- align-items: center;
75
- padding: 12px;
76
- background: #f1f5f9;
77
- border-radius: 8px;
78
- margin-bottom: 12px;
79
- font-size: 14px;
80
- }
81
-
82
- .status-dot {
83
- width: 8px;
84
- height: 8px;
85
- border-radius: 50%;
86
- margin-right: 10px;
87
- }
88
-
89
- .status-desc {
90
- font-size: 12px;
91
- color: #64748b;
92
- margin-top: 2px;
93
- }
94
-
95
- .dot-main { background: #ef4444; box-shadow: 0 0 8px rgba(239, 68, 68, 0.4); }
96
- .dot-worker { background: #3b82f6; box-shadow: 0 0 8px rgba(59, 130, 246, 0.4); }
97
-
98
- .actions {
99
- display: flex;
100
- flex-direction: column;
101
- gap: 12px;
102
- }
103
-
104
- button {
105
- display: flex;
106
- align-items: center;
107
- justify-content: center;
108
- width: 100%;
109
- padding: 12px;
110
- border: none;
111
- border-radius: 8px;
112
- font-size: 14px;
113
- font-weight: 600;
114
- cursor: pointer;
115
- transition: all 0.2s ease;
116
- }
117
-
118
- .btn-start {
119
- background: var(--accent-color);
120
- color: white;
121
- }
122
- .btn-start:hover { background: var(--accent-hover); transform: translateY(-1px); }
123
- .btn-start:active { transform: translateY(0); }
124
-
125
- .btn-stop {
126
- background: #fff;
127
- color: var(--danger-color);
128
- border: 1px solid var(--danger-color);
129
- }
130
- .btn-stop:hover { background: #fef2f2; }
131
-
132
- .info-tip {
133
- margin-top: 20px;
134
- font-size: 12px;
135
- color: var(--text-secondary);
136
- text-align: center;
137
- background: #f8fafc;
138
- padding: 8px;
139
- border-radius: 6px;
140
- border: 1px dashed #cbd5e1;
141
- }
142
-
143
- /* 右侧日志面板 */
144
- .log-panel {
145
- background: #1e293b; /* 深色背景用于日志 */
146
- border-radius: var(--border-radius);
147
- box-shadow: var(--shadow-md);
148
- display: flex;
149
- flex-direction: column;
150
- overflow: hidden;
151
- }
152
-
153
- .log-header {
154
- padding: 16px 24px;
155
- border-bottom: 1px solid #334155;
156
- display: flex;
157
- justify-content: space-between;
158
- align-items: center;
159
- background: #0f172a;
160
- }
161
-
162
- .log-header h2 {
163
- color: #e2e8f0;
164
- font-size: 16px;
165
- font-weight: 600;
166
- display: flex;
167
- align-items: center;
168
- gap: 8px;
169
- }
170
-
171
- .log-box {
172
- flex: 1;
173
- padding: 20px;
174
- overflow-y: auto;
175
- font-family: var(--font-mono);
176
- font-size: 13px;
177
- line-height: 1.8;
178
- }
179
-
180
- /* 滚动条美化 */
181
- .log-box::-webkit-scrollbar { width: 6px; }
182
- .log-box::-webkit-scrollbar-track { background: #1e293b; }
183
- .log-box::-webkit-scrollbar-thumb { background: #475569; border-radius: 3px; }
184
-
185
- /* 日志条目样式 */
186
- .log-item {
187
- display: flex;
188
- margin-bottom: 6px;
189
- animation: fadeIn 0.3s ease;
190
- }
191
-
192
- @keyframes fadeIn {
193
- from { opacity: 0; transform: translateY(5px); }
194
- to { opacity: 1; transform: translateY(0); }
195
- }
196
-
197
- .log-time {
198
- color: #64748b;
199
- margin-right: 12px;
200
- min-width: 85px;
201
- }
202
-
203
- .log-content { color: #e2e8f0; }
204
- .log-type-success .log-content { color: #4ade80; }
205
- .log-type-info .log-content { color: #60a5fa; }
206
- .log-type-error .log-content { color: #f87171; }
207
-
208
- @media (max-width: 768px) {
209
- .dashboard { grid-template-columns: 1fr; height: auto; }
210
- body { height: auto; }
211
- .log-panel { height: 400px; }
212
- }