skill-base 2.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 (51) hide show
  1. package/README.md +141 -0
  2. package/bin/skill-base.js +53 -0
  3. package/data/.gitkeep +0 -0
  4. package/package.json +36 -0
  5. package/src/database.js +119 -0
  6. package/src/index.js +88 -0
  7. package/src/middleware/.gitkeep +0 -0
  8. package/src/middleware/admin.js +23 -0
  9. package/src/middleware/auth.js +96 -0
  10. package/src/middleware/error.js +23 -0
  11. package/src/models/.gitkeep +0 -0
  12. package/src/models/skill.js +57 -0
  13. package/src/models/user.js +130 -0
  14. package/src/models/version.js +57 -0
  15. package/src/routes/.gitkeep +0 -0
  16. package/src/routes/auth.js +173 -0
  17. package/src/routes/collaborators.js +260 -0
  18. package/src/routes/init.js +86 -0
  19. package/src/routes/publish.js +108 -0
  20. package/src/routes/skills.js +119 -0
  21. package/src/routes/users.js +169 -0
  22. package/src/utils/.gitkeep +0 -0
  23. package/src/utils/crypto.js +35 -0
  24. package/src/utils/permission.js +45 -0
  25. package/src/utils/zip.js +35 -0
  26. package/static/admin/users.html +593 -0
  27. package/static/cli-code.html +203 -0
  28. package/static/css/.gitkeep +0 -0
  29. package/static/css/style.css +1567 -0
  30. package/static/diff.html +466 -0
  31. package/static/file.html +443 -0
  32. package/static/index.html +251 -0
  33. package/static/js/.gitkeep +0 -0
  34. package/static/js/admin/users.js +346 -0
  35. package/static/js/app.js +508 -0
  36. package/static/js/auth.js +151 -0
  37. package/static/js/cli-code.js +184 -0
  38. package/static/js/collaborators.js +283 -0
  39. package/static/js/diff.js +540 -0
  40. package/static/js/file.js +619 -0
  41. package/static/js/i18n.js +739 -0
  42. package/static/js/index.js +168 -0
  43. package/static/js/publish.js +718 -0
  44. package/static/js/settings.js +124 -0
  45. package/static/js/setup.js +157 -0
  46. package/static/js/skill.js +808 -0
  47. package/static/login.html +82 -0
  48. package/static/publish.html +459 -0
  49. package/static/settings.html +163 -0
  50. package/static/setup.html +101 -0
  51. package/static/skill.html +851 -0
@@ -0,0 +1,1567 @@
1
+ /* ========================================
2
+ Skill Base - 全局样式
3
+ ======================================== */
4
+
5
+ @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap');
6
+
7
+ /* CSS Reset */
8
+ *,
9
+ *::before,
10
+ *::after {
11
+ box-sizing: border-box;
12
+ margin: 0;
13
+ padding: 0;
14
+ }
15
+
16
+ html {
17
+ font-size: 16px;
18
+ -webkit-text-size-adjust: 100%;
19
+ }
20
+
21
+ body {
22
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
23
+ line-height: 1.6;
24
+ color: var(--text-color);
25
+ background-color: var(--bg-color);
26
+ min-height: 100vh;
27
+ }
28
+
29
+ img, video {
30
+ max-width: 100%;
31
+ height: auto;
32
+ }
33
+
34
+ a {
35
+ color: var(--primary-color);
36
+ text-decoration: none;
37
+ }
38
+
39
+ a:hover {
40
+ text-decoration: underline;
41
+ }
42
+
43
+ ul, ol {
44
+ list-style: none;
45
+ }
46
+
47
+ button, input, textarea, select {
48
+ font-family: inherit;
49
+ font-size: inherit;
50
+ }
51
+
52
+ /* ========================================
53
+ CSS Custom Properties (色彩变量)
54
+ ======================================== */
55
+ :root {
56
+ /* 主色调 */
57
+ --primary-color: #2563eb;
58
+ --primary-hover: #1d4ed8;
59
+ --primary-light: #dbeafe;
60
+
61
+ /* 状态色 */
62
+ --success-color: #16a34a;
63
+ --success-light: #dcfce7;
64
+ --warning-color: #ea580c;
65
+ --warning-light: #ffedd5;
66
+ --error-color: #dc2626;
67
+ --error-light: #fee2e2;
68
+ --info-color: #0ea5e9;
69
+ --info-light: #e0f2fe;
70
+
71
+ /* 中性色 */
72
+ --bg-color: #f8fafc;
73
+ --text-color: #1e293b;
74
+ --text-secondary: #64748b;
75
+ --text-muted: #94a3b8;
76
+ --border-color: #e2e8f0;
77
+ --white: #ffffff;
78
+ --black: #000000;
79
+
80
+ /* 阴影 */
81
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
82
+ --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
83
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
84
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
85
+
86
+ /* 圆角 */
87
+ --radius-sm: 4px;
88
+ --radius: 8px;
89
+ --radius-lg: 12px;
90
+ --radius-full: 9999px;
91
+
92
+ /* 间距 */
93
+ --spacing-xs: 0.25rem;
94
+ --spacing-sm: 0.5rem;
95
+ --spacing-md: 1rem;
96
+ --spacing-lg: 1.5rem;
97
+ --spacing-xl: 2rem;
98
+
99
+ /* 过渡 */
100
+ --transition: all 0.2s ease;
101
+ }
102
+
103
+ /* ========================================
104
+ 应用壳:Developer Tools 深色主题
105
+ (在 body 上添加 class="app-devtools";登录页用 .login-body 不加此类)
106
+ ======================================== */
107
+ body.app-devtools {
108
+ --primary-color: #22c55e;
109
+ --primary-hover: #16a34a;
110
+ --primary-light: rgba(34, 197, 94, 0.2);
111
+ --success-color: #4ade80;
112
+ --success-light: rgba(74, 222, 128, 0.14);
113
+ --warning-color: #fb923c;
114
+ --warning-light: rgba(251, 146, 60, 0.16);
115
+ --error-color: #f87171;
116
+ --error-light: rgba(248, 113, 113, 0.16);
117
+ --info-color: #38bdf8;
118
+ --info-light: rgba(56, 189, 248, 0.14);
119
+ --bg-color: #0f172a;
120
+ --text-color: #f1f5f9;
121
+ --text-secondary: #94a3b8;
122
+ --text-muted: #64748b;
123
+ --border-color: #334155;
124
+ --white: #1e293b;
125
+ --black: #020617;
126
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
127
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
128
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
129
+ --shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.45);
130
+ font-family: 'IBM Plex Sans', system-ui, sans-serif;
131
+ color: var(--text-color);
132
+ background-color: var(--bg-color);
133
+ }
134
+
135
+ body.app-devtools .page-content {
136
+ background-image:
137
+ linear-gradient(rgba(51, 65, 85, 0.1) 1px, transparent 1px),
138
+ linear-gradient(90deg, rgba(51, 65, 85, 0.1) 1px, transparent 1px);
139
+ background-size: 24px 24px;
140
+ }
141
+
142
+ body.app-devtools .navbar {
143
+ background-color: #0c1222;
144
+ border-bottom: 1px solid var(--border-color);
145
+ box-shadow: none;
146
+ }
147
+
148
+ body.app-devtools .navbar-nav a:hover,
149
+ body.app-devtools .navbar-nav a.active {
150
+ color: #7dd3fc;
151
+ }
152
+
153
+ body.app-devtools .btn-secondary {
154
+ background-color: #252f42;
155
+ color: var(--text-color);
156
+ border-color: var(--border-color);
157
+ }
158
+
159
+ body.app-devtools .btn-secondary:hover:not(:disabled) {
160
+ background-color: #2d3b52;
161
+ border-color: #475569;
162
+ }
163
+
164
+ body.app-devtools input[type="text"],
165
+ body.app-devtools input[type="email"],
166
+ body.app-devtools input[type="password"],
167
+ body.app-devtools input[type="search"],
168
+ body.app-devtools input[type="number"],
169
+ body.app-devtools input[type="url"],
170
+ body.app-devtools textarea,
171
+ body.app-devtools select {
172
+ background-color: #0f172a;
173
+ color: var(--text-color);
174
+ border-color: var(--border-color);
175
+ }
176
+
177
+ body.app-devtools input:focus,
178
+ body.app-devtools textarea:focus,
179
+ body.app-devtools select:focus {
180
+ border-color: #7dd3fc;
181
+ box-shadow: 0 0 0 2px rgba(125, 211, 252, 0.18);
182
+ }
183
+
184
+ body.app-devtools input::placeholder,
185
+ body.app-devtools textarea::placeholder {
186
+ color: #64748b;
187
+ }
188
+
189
+ body.app-devtools .file-tree {
190
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
191
+ }
192
+
193
+ body.app-devtools .skill-card {
194
+ border: 1px solid var(--border-color);
195
+ box-shadow: var(--shadow-sm);
196
+ background-color: var(--white);
197
+ }
198
+
199
+ body.app-devtools .skill-card:hover {
200
+ border-color: #475569;
201
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
202
+ }
203
+
204
+ body.app-devtools .skeleton-card {
205
+ border: 1px solid var(--border-color);
206
+ }
207
+
208
+ body.app-devtools .markdown-body th {
209
+ background-color: #0f172a;
210
+ }
211
+
212
+ body.app-devtools .file-preview-content pre,
213
+ body.app-devtools .file-content-body pre,
214
+ body.app-devtools .markdown-body pre {
215
+ background-color: #0f172a;
216
+ border: 1px solid var(--border-color);
217
+ }
218
+
219
+ body.app-devtools .markdown-body code {
220
+ background-color: #0f172a;
221
+ }
222
+
223
+ body.app-devtools .loading-overlay::before {
224
+ background-color: rgba(15, 23, 42, 0.88);
225
+ }
226
+
227
+ body.app-devtools .loading-overlay::after {
228
+ border-color: var(--border-color);
229
+ border-top-color: #7dd3fc;
230
+ }
231
+
232
+ body.app-devtools .diff-line.context {
233
+ background-color: #1e293b;
234
+ }
235
+
236
+ body.app-devtools .diff-line.added .diff-line-num {
237
+ background-color: rgba(34, 197, 94, 0.22);
238
+ }
239
+
240
+ body.app-devtools .diff-line.removed .diff-line-num {
241
+ background-color: rgba(248, 113, 113, 0.22);
242
+ }
243
+
244
+ body.app-devtools .d2h-wrapper,
245
+ body.app-devtools .d2h-file-wrapper {
246
+ background: #1e293b !important;
247
+ color: #e2e8f0 !important;
248
+ }
249
+
250
+ body.app-devtools .d2h-file-header {
251
+ background: #0f172a !important;
252
+ color: #e2e8f0 !important;
253
+ border-color: var(--border-color) !important;
254
+ }
255
+
256
+ body.app-devtools .d2h-code-line,
257
+ body.app-devtools .d2h-code-line-prefix,
258
+ body.app-devtools .d2h-code-line-ctn {
259
+ border-color: var(--border-color) !important;
260
+ }
261
+
262
+ body.app-devtools .d2h-file-side-diff {
263
+ background: #1e293b !important;
264
+ }
265
+
266
+ body.app-devtools .d2h-code-side-line-prefix {
267
+ background: #0f172a !important;
268
+ color: #64748b !important;
269
+ }
270
+
271
+ body.app-devtools .d2h-ins {
272
+ background-color: rgba(34, 197, 94, 0.18) !important;
273
+ }
274
+
275
+ body.app-devtools .d2h-del {
276
+ background-color: rgba(248, 113, 113, 0.18) !important;
277
+ }
278
+
279
+ body.app-devtools .d2h-info {
280
+ background: #0f172a !important;
281
+ color: #94a3b8 !important;
282
+ }
283
+
284
+ body.app-devtools .navbar-brand-icon {
285
+ flex-shrink: 0;
286
+ opacity: 0.95;
287
+ }
288
+
289
+ /* 主色按钮上的文字:不用 remapped 的 --white(已用作面板底) */
290
+ body.app-devtools .btn-primary,
291
+ body.app-devtools .btn-group .btn.active {
292
+ color: #052e16;
293
+ }
294
+
295
+ body.app-devtools .btn-primary:hover:not(:disabled),
296
+ body.app-devtools .btn-group .btn.active:hover:not(:disabled) {
297
+ color: #022c14;
298
+ }
299
+
300
+ body.app-devtools .fab {
301
+ color: #052e16;
302
+ }
303
+
304
+ body.app-devtools .btn-danger,
305
+ body.app-devtools .btn-danger:hover:not(:disabled) {
306
+ color: #fff;
307
+ }
308
+
309
+ body.app-devtools .file-preview-path,
310
+ body.app-devtools .file-content-path,
311
+ body.app-devtools .diff-file-path,
312
+ body.app-devtools .changed-file-path,
313
+ body.app-devtools .file-preview-list {
314
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
315
+ }
316
+
317
+ /* ========================================
318
+ 容器
319
+ ======================================== */
320
+ .container {
321
+ width: 100%;
322
+ max-width: 1200px;
323
+ margin: 0 auto;
324
+ padding: 0 var(--spacing-md);
325
+ }
326
+
327
+ .container-sm {
328
+ max-width: 640px;
329
+ }
330
+
331
+ .container-md {
332
+ max-width: 768px;
333
+ }
334
+
335
+ .container-lg {
336
+ max-width: 1024px;
337
+ }
338
+
339
+ /* ========================================
340
+ 导航栏
341
+ ======================================== */
342
+ .navbar {
343
+ position: fixed;
344
+ top: 0;
345
+ left: 0;
346
+ right: 0;
347
+ height: 60px;
348
+ background-color: var(--white);
349
+ box-shadow: var(--shadow);
350
+ z-index: 1000;
351
+ display: flex;
352
+ align-items: center;
353
+ }
354
+
355
+ .navbar .container {
356
+ display: flex;
357
+ align-items: center;
358
+ justify-content: space-between;
359
+ height: 100%;
360
+ }
361
+
362
+ .navbar-brand {
363
+ font-size: 1.25rem;
364
+ font-weight: 600;
365
+ color: var(--primary-color);
366
+ display: flex;
367
+ align-items: center;
368
+ gap: var(--spacing-sm);
369
+ }
370
+
371
+ .navbar-brand:hover {
372
+ text-decoration: none;
373
+ }
374
+
375
+ .navbar-nav {
376
+ display: flex;
377
+ align-items: center;
378
+ gap: var(--spacing-lg);
379
+ }
380
+
381
+ .navbar-nav a {
382
+ color: var(--text-color);
383
+ font-weight: 500;
384
+ transition: var(--transition);
385
+ }
386
+
387
+ .navbar-nav a:hover {
388
+ color: var(--primary-color);
389
+ text-decoration: none;
390
+ }
391
+
392
+ .navbar-nav a.active {
393
+ color: var(--primary-color);
394
+ }
395
+
396
+ .navbar-user {
397
+ display: flex;
398
+ align-items: center;
399
+ gap: var(--spacing-md);
400
+ }
401
+
402
+ .navbar-user .username {
403
+ color: var(--text-secondary);
404
+ font-size: 0.875rem;
405
+ }
406
+
407
+ /* 用户下拉菜单 */
408
+ .navbar-user-dropdown {
409
+ position: relative;
410
+ }
411
+
412
+ .navbar-user-btn {
413
+ display: flex;
414
+ align-items: center;
415
+ gap: var(--spacing-xs);
416
+ padding: var(--spacing-sm) var(--spacing-md);
417
+ background-color: transparent;
418
+ border: 1px solid var(--border-color);
419
+ border-radius: var(--radius);
420
+ cursor: pointer;
421
+ transition: var(--transition);
422
+ color: var(--text-color);
423
+ font-size: 0.875rem;
424
+ }
425
+
426
+ .navbar-user-btn:hover {
427
+ background-color: var(--bg-color);
428
+ border-color: var(--primary-color);
429
+ }
430
+
431
+ .navbar-user-menu {
432
+ position: absolute;
433
+ top: calc(100% + var(--spacing-sm));
434
+ right: 0;
435
+ min-width: 200px;
436
+ background-color: var(--white);
437
+ border: 1px solid var(--border-color);
438
+ border-radius: var(--radius);
439
+ box-shadow: var(--shadow-lg);
440
+ padding: var(--spacing-sm);
441
+ z-index: 1000;
442
+ opacity: 0;
443
+ visibility: hidden;
444
+ transform: translateY(-10px);
445
+ transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
446
+ }
447
+
448
+ .navbar-user-dropdown.active .navbar-user-menu {
449
+ opacity: 1;
450
+ visibility: visible;
451
+ transform: translateY(0);
452
+ }
453
+
454
+ .navbar-user-menu-item {
455
+ display: flex;
456
+ align-items: center;
457
+ gap: var(--spacing-sm);
458
+ padding: var(--spacing-sm) var(--spacing-md);
459
+ color: var(--text-color);
460
+ font-size: 0.875rem;
461
+ border-radius: var(--radius-sm);
462
+ cursor: pointer;
463
+ transition: var(--transition);
464
+ text-decoration: none;
465
+ width: 100%;
466
+ border: none;
467
+ background: none;
468
+ text-align: left;
469
+ }
470
+
471
+ .navbar-user-menu-item:hover {
472
+ background-color: var(--bg-color);
473
+ }
474
+
475
+ .navbar-user-menu-divider {
476
+ height: 1px;
477
+ background-color: var(--border-color);
478
+ margin: var(--spacing-sm) 0;
479
+ }
480
+
481
+ .navbar-user-logout {
482
+ color: var(--error-color);
483
+ }
484
+
485
+ /* 语言切换下拉 */
486
+ .lang-switcher {
487
+ position: relative;
488
+ display: inline-flex;
489
+ }
490
+
491
+ .lang-switcher-trigger {
492
+ display: flex;
493
+ align-items: center;
494
+ gap: 5px;
495
+ padding: 6px 10px;
496
+ background: transparent;
497
+ border: 1px solid var(--border-color);
498
+ border-radius: 8px;
499
+ cursor: pointer;
500
+ font-size: 0.8125rem;
501
+ font-weight: 500;
502
+ color: var(--text-secondary);
503
+ transition: var(--transition);
504
+ white-space: nowrap;
505
+ line-height: 1;
506
+ }
507
+
508
+ .lang-switcher-trigger:hover {
509
+ border-color: var(--primary-color);
510
+ color: var(--primary-color);
511
+ background-color: var(--bg-color);
512
+ }
513
+
514
+ .lang-switcher.active .lang-switcher-trigger {
515
+ border-color: var(--primary-color);
516
+ color: var(--primary-color);
517
+ }
518
+
519
+ .lang-switcher-trigger svg {
520
+ flex-shrink: 0;
521
+ }
522
+
523
+ .lang-chevron {
524
+ transition: transform 0.2s ease;
525
+ }
526
+
527
+ .lang-switcher.active .lang-chevron {
528
+ transform: rotate(180deg);
529
+ }
530
+
531
+ .lang-switcher-menu {
532
+ display: none;
533
+ position: absolute;
534
+ top: calc(100% + 6px);
535
+ right: 0;
536
+ min-width: 108px;
537
+ background: var(--bg-secondary);
538
+ border: 1px solid var(--border-color);
539
+ border-radius: 10px;
540
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
541
+ overflow: hidden;
542
+ z-index: 200;
543
+ padding: 4px;
544
+ }
545
+
546
+ .lang-switcher.active .lang-switcher-menu {
547
+ display: block;
548
+ }
549
+
550
+ .lang-switcher-option {
551
+ display: flex;
552
+ align-items: center;
553
+ width: 100%;
554
+ padding: 8px 12px;
555
+ background: transparent;
556
+ border: none;
557
+ border-radius: 6px;
558
+ cursor: pointer;
559
+ font-size: 0.8125rem;
560
+ color: var(--text-secondary);
561
+ transition: var(--transition);
562
+ text-align: left;
563
+ white-space: nowrap;
564
+ }
565
+
566
+ .lang-switcher-option:hover {
567
+ background: var(--bg-color);
568
+ color: var(--text-primary);
569
+ }
570
+
571
+ .lang-switcher-option.active {
572
+ color: var(--primary-color);
573
+ font-weight: 600;
574
+ background: var(--bg-color);
575
+ }
576
+
577
+ /* 页面内容偏移(为固定导航栏留出空间) */
578
+ .page-content {
579
+ padding-top: 80px;
580
+ padding-bottom: var(--spacing-xl);
581
+ min-height: calc(100vh - 60px);
582
+ }
583
+
584
+ /* ========================================
585
+ 卡片
586
+ ======================================== */
587
+ .card {
588
+ background-color: var(--white);
589
+ border-radius: var(--radius);
590
+ box-shadow: var(--shadow);
591
+ padding: var(--spacing-lg);
592
+ }
593
+
594
+ .card-header {
595
+ margin-bottom: var(--spacing-md);
596
+ padding-bottom: var(--spacing-md);
597
+ border-bottom: 1px solid var(--border-color);
598
+ }
599
+
600
+ .card-title {
601
+ font-size: 1.125rem;
602
+ font-weight: 600;
603
+ color: var(--text-color);
604
+ }
605
+
606
+ .card-subtitle {
607
+ font-size: 0.875rem;
608
+ color: var(--text-secondary);
609
+ margin-top: var(--spacing-xs);
610
+ }
611
+
612
+ .card-body {
613
+ color: var(--text-color);
614
+ }
615
+
616
+ .card-footer {
617
+ margin-top: var(--spacing-md);
618
+ padding-top: var(--spacing-md);
619
+ border-top: 1px solid var(--border-color);
620
+ }
621
+
622
+ /* ========================================
623
+ 按钮
624
+ ======================================== */
625
+ .btn {
626
+ display: inline-flex;
627
+ align-items: center;
628
+ justify-content: center;
629
+ gap: var(--spacing-sm);
630
+ padding: 0.5rem 1rem;
631
+ font-size: 0.875rem;
632
+ font-weight: 500;
633
+ line-height: 1.5;
634
+ border: 1px solid transparent;
635
+ border-radius: var(--radius);
636
+ cursor: pointer;
637
+ transition: var(--transition);
638
+ text-decoration: none;
639
+ white-space: nowrap;
640
+ }
641
+
642
+ .btn:hover {
643
+ text-decoration: none;
644
+ }
645
+
646
+ .btn:disabled {
647
+ opacity: 0.6;
648
+ cursor: not-allowed;
649
+ }
650
+
651
+ .btn-primary {
652
+ background-color: var(--primary-color);
653
+ color: var(--white);
654
+ border-color: var(--primary-color);
655
+ }
656
+
657
+ .btn-primary:hover:not(:disabled) {
658
+ background-color: var(--primary-hover);
659
+ border-color: var(--primary-hover);
660
+ }
661
+
662
+ .btn-secondary {
663
+ background-color: var(--white);
664
+ color: var(--text-color);
665
+ border-color: var(--border-color);
666
+ }
667
+
668
+ .btn-secondary:hover:not(:disabled) {
669
+ background-color: var(--bg-color);
670
+ border-color: var(--text-muted);
671
+ }
672
+
673
+ .btn-danger {
674
+ background-color: var(--error-color);
675
+ color: var(--white);
676
+ border-color: var(--error-color);
677
+ }
678
+
679
+ .btn-danger:hover:not(:disabled) {
680
+ background-color: #b91c1c;
681
+ border-color: #b91c1c;
682
+ }
683
+
684
+ .btn-success {
685
+ background-color: var(--success-color);
686
+ color: var(--white);
687
+ border-color: var(--success-color);
688
+ }
689
+
690
+ .btn-success:hover:not(:disabled) {
691
+ background-color: #15803d;
692
+ border-color: #15803d;
693
+ }
694
+
695
+ .btn-sm {
696
+ padding: 0.25rem 0.75rem;
697
+ font-size: 0.75rem;
698
+ }
699
+
700
+ .btn-lg {
701
+ padding: 0.75rem 1.5rem;
702
+ font-size: 1rem;
703
+ }
704
+
705
+ .btn-block {
706
+ display: flex;
707
+ width: 100%;
708
+ }
709
+
710
+ /* ========================================
711
+ 表单
712
+ ======================================== */
713
+ .form-group {
714
+ margin-bottom: var(--spacing-md);
715
+ }
716
+
717
+ .form-label {
718
+ display: block;
719
+ margin-bottom: var(--spacing-xs);
720
+ font-size: 0.875rem;
721
+ font-weight: 500;
722
+ color: var(--text-color);
723
+ }
724
+
725
+ .form-label.required::after {
726
+ content: ' *';
727
+ color: var(--error-color);
728
+ }
729
+
730
+ input[type="text"],
731
+ input[type="email"],
732
+ input[type="password"],
733
+ input[type="search"],
734
+ input[type="number"],
735
+ input[type="url"],
736
+ textarea,
737
+ select {
738
+ width: 100%;
739
+ padding: 0.625rem 0.875rem;
740
+ font-size: 0.875rem;
741
+ line-height: 1.5;
742
+ color: var(--text-color);
743
+ background-color: var(--white);
744
+ border: 1px solid var(--border-color);
745
+ border-radius: var(--radius);
746
+ transition: var(--transition);
747
+ }
748
+
749
+ input:focus,
750
+ textarea:focus,
751
+ select:focus {
752
+ outline: none;
753
+ border-color: var(--primary-color);
754
+ box-shadow: 0 0 0 3px var(--primary-light);
755
+ }
756
+
757
+ input::placeholder,
758
+ textarea::placeholder {
759
+ color: var(--text-muted);
760
+ }
761
+
762
+ input:disabled,
763
+ textarea:disabled,
764
+ select:disabled {
765
+ background-color: var(--bg-color);
766
+ cursor: not-allowed;
767
+ }
768
+
769
+ input.error,
770
+ textarea.error,
771
+ select.error {
772
+ border-color: var(--error-color);
773
+ }
774
+
775
+ input.error:focus,
776
+ textarea.error:focus,
777
+ select.error:focus {
778
+ box-shadow: 0 0 0 3px var(--error-light);
779
+ }
780
+
781
+ textarea {
782
+ resize: vertical;
783
+ min-height: 100px;
784
+ }
785
+
786
+ .form-hint {
787
+ margin-top: var(--spacing-xs);
788
+ font-size: 0.75rem;
789
+ color: var(--text-secondary);
790
+ }
791
+
792
+ .form-error {
793
+ margin-top: var(--spacing-xs);
794
+ font-size: 0.75rem;
795
+ color: var(--error-color);
796
+ }
797
+
798
+ /* ========================================
799
+ 搜索栏
800
+ ======================================== */
801
+ .search-bar {
802
+ position: relative;
803
+ width: 100%;
804
+ }
805
+
806
+ .search-bar input {
807
+ padding-left: 2.5rem;
808
+ padding-right: 2.5rem;
809
+ }
810
+
811
+ .search-bar .search-icon {
812
+ position: absolute;
813
+ left: 0.875rem;
814
+ top: 50%;
815
+ transform: translateY(-50%);
816
+ color: var(--text-muted);
817
+ pointer-events: none;
818
+ }
819
+
820
+ .search-bar .clear-btn {
821
+ position: absolute;
822
+ right: 0.5rem;
823
+ top: 50%;
824
+ transform: translateY(-50%);
825
+ background: none;
826
+ border: none;
827
+ color: var(--text-muted);
828
+ cursor: pointer;
829
+ padding: 0.25rem;
830
+ display: none;
831
+ }
832
+
833
+ .search-bar input:not(:placeholder-shown) + .search-icon + .clear-btn,
834
+ .search-bar .clear-btn.visible {
835
+ display: block;
836
+ }
837
+
838
+ /* ========================================
839
+ 文件树
840
+ ======================================== */
841
+ .file-tree {
842
+ font-family: 'SF Mono', Monaco, 'Courier New', monospace;
843
+ font-size: 0.875rem;
844
+ line-height: 1.8;
845
+ }
846
+
847
+ .file-tree ul {
848
+ padding-left: var(--spacing-lg);
849
+ }
850
+
851
+ .file-tree li {
852
+ position: relative;
853
+ }
854
+
855
+ .file-tree-item {
856
+ display: flex;
857
+ align-items: center;
858
+ gap: var(--spacing-sm);
859
+ padding: var(--spacing-xs) var(--spacing-sm);
860
+ border-radius: var(--radius-sm);
861
+ cursor: pointer;
862
+ transition: var(--transition);
863
+ }
864
+
865
+ .file-tree-item:hover {
866
+ background-color: var(--bg-color);
867
+ }
868
+
869
+ .file-tree-item.selected {
870
+ background-color: var(--primary-light);
871
+ color: var(--primary-color);
872
+ }
873
+
874
+ .file-tree-item .icon {
875
+ width: 16px;
876
+ height: 16px;
877
+ flex-shrink: 0;
878
+ }
879
+
880
+ .file-tree-item .name {
881
+ flex: 1;
882
+ overflow: hidden;
883
+ text-overflow: ellipsis;
884
+ white-space: nowrap;
885
+ }
886
+
887
+ .file-tree-folder > .file-tree-item::before {
888
+ content: '▶';
889
+ font-size: 0.625rem;
890
+ margin-right: var(--spacing-xs);
891
+ transition: var(--transition);
892
+ }
893
+
894
+ .file-tree-folder.open > .file-tree-item::before {
895
+ transform: rotate(90deg);
896
+ }
897
+
898
+ /* ========================================
899
+ 拖拽上传区域
900
+ ======================================== */
901
+ .drop-zone {
902
+ border: 2px dashed var(--border-color);
903
+ border-radius: var(--radius);
904
+ padding: var(--spacing-xl);
905
+ text-align: center;
906
+ transition: var(--transition);
907
+ cursor: pointer;
908
+ }
909
+
910
+ .drop-zone:hover,
911
+ .drop-zone.dragover {
912
+ border-color: var(--primary-color);
913
+ background-color: var(--primary-light);
914
+ }
915
+
916
+ .drop-zone-icon {
917
+ font-size: 3rem;
918
+ color: var(--text-muted);
919
+ margin-bottom: var(--spacing-md);
920
+ }
921
+
922
+ .drop-zone-text {
923
+ color: var(--text-secondary);
924
+ margin-bottom: var(--spacing-sm);
925
+ }
926
+
927
+ .drop-zone-hint {
928
+ font-size: 0.75rem;
929
+ color: var(--text-muted);
930
+ }
931
+
932
+ .drop-zone input[type="file"] {
933
+ display: none;
934
+ }
935
+
936
+ /* ========================================
937
+ 版本标签
938
+ ======================================== */
939
+ .version-tag {
940
+ display: inline-flex;
941
+ align-items: center;
942
+ gap: var(--spacing-xs);
943
+ padding: 0.125rem 0.5rem;
944
+ font-size: 0.75rem;
945
+ font-weight: 500;
946
+ border-radius: var(--radius-full);
947
+ background-color: var(--bg-color);
948
+ color: var(--text-secondary);
949
+ }
950
+
951
+ .version-tag.latest {
952
+ background-color: var(--success-light);
953
+ color: var(--success-color);
954
+ }
955
+
956
+ .version-tag.current {
957
+ background-color: var(--primary-light);
958
+ color: var(--primary-color);
959
+ }
960
+
961
+ /* ========================================
962
+ Diff 样式
963
+ ======================================== */
964
+ .diff-view {
965
+ font-family: 'SF Mono', Monaco, 'Courier New', monospace;
966
+ font-size: 0.8125rem;
967
+ line-height: 1.6;
968
+ border: 1px solid var(--border-color);
969
+ border-radius: var(--radius);
970
+ overflow: hidden;
971
+ }
972
+
973
+ .diff-header {
974
+ background-color: var(--bg-color);
975
+ padding: var(--spacing-sm) var(--spacing-md);
976
+ border-bottom: 1px solid var(--border-color);
977
+ font-weight: 500;
978
+ }
979
+
980
+ .diff-content {
981
+ overflow-x: auto;
982
+ }
983
+
984
+ .diff-line {
985
+ display: flex;
986
+ min-height: 1.6em;
987
+ }
988
+
989
+ .diff-line-num {
990
+ width: 50px;
991
+ padding: 0 var(--spacing-sm);
992
+ text-align: right;
993
+ color: var(--text-muted);
994
+ background-color: var(--bg-color);
995
+ border-right: 1px solid var(--border-color);
996
+ user-select: none;
997
+ flex-shrink: 0;
998
+ }
999
+
1000
+ .diff-line-content {
1001
+ flex: 1;
1002
+ padding: 0 var(--spacing-md);
1003
+ white-space: pre;
1004
+ }
1005
+
1006
+ .diff-line.added {
1007
+ background-color: var(--success-light);
1008
+ }
1009
+
1010
+ .diff-line.added .diff-line-num {
1011
+ background-color: #bbf7d0;
1012
+ }
1013
+
1014
+ .diff-line.removed {
1015
+ background-color: var(--error-light);
1016
+ }
1017
+
1018
+ .diff-line.removed .diff-line-num {
1019
+ background-color: #fecaca;
1020
+ }
1021
+
1022
+ .diff-line.context {
1023
+ background-color: var(--white);
1024
+ }
1025
+
1026
+ /* ========================================
1027
+ Toast 通知
1028
+ ======================================== */
1029
+ .toast-container {
1030
+ position: fixed;
1031
+ top: 80px;
1032
+ right: var(--spacing-md);
1033
+ z-index: 2000;
1034
+ display: flex;
1035
+ flex-direction: column;
1036
+ gap: var(--spacing-sm);
1037
+ pointer-events: none;
1038
+ }
1039
+
1040
+ .toast {
1041
+ display: flex;
1042
+ align-items: center;
1043
+ gap: var(--spacing-sm);
1044
+ padding: var(--spacing-md) var(--spacing-lg);
1045
+ background-color: var(--white);
1046
+ border-radius: var(--radius);
1047
+ box-shadow: var(--shadow-lg);
1048
+ pointer-events: auto;
1049
+ animation: toast-in 0.3s ease;
1050
+ max-width: 400px;
1051
+ }
1052
+
1053
+ .toast.toast-out {
1054
+ animation: toast-out 0.3s ease forwards;
1055
+ }
1056
+
1057
+ @keyframes toast-in {
1058
+ from {
1059
+ opacity: 0;
1060
+ transform: translateX(100%);
1061
+ }
1062
+ to {
1063
+ opacity: 1;
1064
+ transform: translateX(0);
1065
+ }
1066
+ }
1067
+
1068
+ @keyframes toast-out {
1069
+ from {
1070
+ opacity: 1;
1071
+ transform: translateX(0);
1072
+ }
1073
+ to {
1074
+ opacity: 0;
1075
+ transform: translateX(100%);
1076
+ }
1077
+ }
1078
+
1079
+ .toast-icon {
1080
+ flex-shrink: 0;
1081
+ width: 20px;
1082
+ height: 20px;
1083
+ }
1084
+
1085
+ .toast-message {
1086
+ flex: 1;
1087
+ font-size: 0.875rem;
1088
+ color: var(--text-color);
1089
+ }
1090
+
1091
+ .toast.success {
1092
+ border-left: 4px solid var(--success-color);
1093
+ }
1094
+
1095
+ .toast.success .toast-icon {
1096
+ color: var(--success-color);
1097
+ }
1098
+
1099
+ .toast.error {
1100
+ border-left: 4px solid var(--error-color);
1101
+ }
1102
+
1103
+ .toast.error .toast-icon {
1104
+ color: var(--error-color);
1105
+ }
1106
+
1107
+ .toast.warning {
1108
+ border-left: 4px solid var(--warning-color);
1109
+ }
1110
+
1111
+ .toast.warning .toast-icon {
1112
+ color: var(--warning-color);
1113
+ }
1114
+
1115
+ .toast.info {
1116
+ border-left: 4px solid var(--info-color);
1117
+ }
1118
+
1119
+ .toast.info .toast-icon {
1120
+ color: var(--info-color);
1121
+ }
1122
+
1123
+ /* ========================================
1124
+ Loading 状态
1125
+ ======================================== */
1126
+ .loading {
1127
+ display: flex;
1128
+ align-items: center;
1129
+ justify-content: center;
1130
+ padding: var(--spacing-xl);
1131
+ color: var(--text-secondary);
1132
+ }
1133
+
1134
+ .spinner {
1135
+ width: 24px;
1136
+ height: 24px;
1137
+ border: 3px solid var(--border-color);
1138
+ border-top-color: var(--primary-color);
1139
+ border-radius: 50%;
1140
+ animation: spin 0.8s linear infinite;
1141
+ }
1142
+
1143
+ .spinner-sm {
1144
+ width: 16px;
1145
+ height: 16px;
1146
+ border-width: 2px;
1147
+ }
1148
+
1149
+ .spinner-lg {
1150
+ width: 40px;
1151
+ height: 40px;
1152
+ border-width: 4px;
1153
+ }
1154
+
1155
+ @keyframes spin {
1156
+ to {
1157
+ transform: rotate(360deg);
1158
+ }
1159
+ }
1160
+
1161
+ .loading-overlay {
1162
+ position: fixed;
1163
+ top: 0;
1164
+ left: 0;
1165
+ right: 0;
1166
+ bottom: 0;
1167
+ background-color: rgba(255, 255, 255, 0.8);
1168
+ display: flex;
1169
+ align-items: center;
1170
+ justify-content: center;
1171
+ z-index: 3000;
1172
+ }
1173
+
1174
+ .skeleton {
1175
+ background: linear-gradient(90deg, var(--bg-color) 25%, var(--border-color) 50%, var(--bg-color) 75%);
1176
+ background-size: 200% 100%;
1177
+ animation: skeleton-loading 1.5s infinite;
1178
+ border-radius: var(--radius-sm);
1179
+ }
1180
+
1181
+ @keyframes skeleton-loading {
1182
+ 0% {
1183
+ background-position: 200% 0;
1184
+ }
1185
+ 100% {
1186
+ background-position: -200% 0;
1187
+ }
1188
+ }
1189
+
1190
+ /* ========================================
1191
+ 工具类
1192
+ ======================================== */
1193
+ .text-center { text-align: center; }
1194
+ .text-left { text-align: left; }
1195
+ .text-right { text-align: right; }
1196
+
1197
+ .text-primary { color: var(--primary-color); }
1198
+ .text-success { color: var(--success-color); }
1199
+ .text-warning { color: var(--warning-color); }
1200
+ .text-error { color: var(--error-color); }
1201
+ .text-muted { color: var(--text-muted); }
1202
+ .text-secondary { color: var(--text-secondary); }
1203
+
1204
+ .font-bold { font-weight: 600; }
1205
+ .font-medium { font-weight: 500; }
1206
+ .font-normal { font-weight: 400; }
1207
+
1208
+ .mt-0 { margin-top: 0; }
1209
+ .mt-1 { margin-top: var(--spacing-sm); }
1210
+ .mt-2 { margin-top: var(--spacing-md); }
1211
+ .mt-3 { margin-top: var(--spacing-lg); }
1212
+ .mt-4 { margin-top: var(--spacing-xl); }
1213
+
1214
+ .mb-0 { margin-bottom: 0; }
1215
+ .mb-1 { margin-bottom: var(--spacing-sm); }
1216
+ .mb-2 { margin-bottom: var(--spacing-md); }
1217
+ .mb-3 { margin-bottom: var(--spacing-lg); }
1218
+ .mb-4 { margin-bottom: var(--spacing-xl); }
1219
+
1220
+ .hidden { display: none !important; }
1221
+ .invisible { visibility: hidden; }
1222
+
1223
+ .flex { display: flex; }
1224
+ .flex-col { flex-direction: column; }
1225
+ .items-center { align-items: center; }
1226
+ .justify-center { justify-content: center; }
1227
+ .justify-between { justify-content: space-between; }
1228
+ .gap-1 { gap: var(--spacing-sm); }
1229
+ .gap-2 { gap: var(--spacing-md); }
1230
+ .gap-3 { gap: var(--spacing-lg); }
1231
+
1232
+ /* ========================================
1233
+ 登录页:Developer Tools 风格
1234
+ (配色与字体参考 ui-ux-pro-max:深色底、JetBrains Mono、CTA 绿)
1235
+ ======================================== */
1236
+ body.login-body {
1237
+ background-color: #0f172a;
1238
+ color: #e2e8f0;
1239
+ }
1240
+
1241
+ .login-page {
1242
+ --login-bg-deep: #0f172a;
1243
+ --login-panel: #1e293b;
1244
+ --login-chrome: #0c1222;
1245
+ --login-border: #334155;
1246
+ --login-text: #f8fafc;
1247
+ --login-muted: #94a3b8;
1248
+ --login-accent: #7dd3fc;
1249
+ --login-string: #86efac;
1250
+ --login-cta: #22c55e;
1251
+ --login-cta-hover: #16a34a;
1252
+ --login-error-bg: rgba(220, 38, 38, 0.15);
1253
+ --login-error-fg: #fca5a5;
1254
+
1255
+ min-height: 100vh;
1256
+ display: flex;
1257
+ align-items: center;
1258
+ justify-content: center;
1259
+ padding: var(--spacing-md);
1260
+ background-color: var(--login-bg-deep);
1261
+ background-image:
1262
+ linear-gradient(rgba(51, 65, 85, 0.12) 1px, transparent 1px),
1263
+ linear-gradient(90deg, rgba(51, 65, 85, 0.12) 1px, transparent 1px);
1264
+ background-size: 24px 24px;
1265
+ font-family: 'IBM Plex Sans', system-ui, sans-serif;
1266
+ }
1267
+
1268
+ .login-devtools {
1269
+ width: 100%;
1270
+ max-width: 420px;
1271
+ border: 1px solid var(--login-border);
1272
+ border-radius: 10px;
1273
+ overflow: hidden;
1274
+ box-shadow:
1275
+ 0 0 0 1px rgba(0, 0, 0, 0.4),
1276
+ 0 24px 48px -12px rgba(0, 0, 0, 0.55);
1277
+ }
1278
+
1279
+ .devtools-chrome {
1280
+ background: var(--login-chrome);
1281
+ border-bottom: 1px solid var(--login-border);
1282
+ }
1283
+
1284
+ .devtools-titlebar {
1285
+ display: flex;
1286
+ align-items: center;
1287
+ gap: var(--spacing-md);
1288
+ padding: 10px 12px;
1289
+ min-height: 40px;
1290
+ }
1291
+
1292
+ .devtools-traffic {
1293
+ display: flex;
1294
+ align-items: center;
1295
+ gap: 6px;
1296
+ flex-shrink: 0;
1297
+ }
1298
+
1299
+ .devtools-dot {
1300
+ width: 10px;
1301
+ height: 10px;
1302
+ border-radius: 50%;
1303
+ display: block;
1304
+ }
1305
+
1306
+ .devtools-dot--close {
1307
+ background: #ff5f57;
1308
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
1309
+ }
1310
+
1311
+ .devtools-dot--min {
1312
+ background: #febc2e;
1313
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
1314
+ }
1315
+
1316
+ .devtools-dot--max {
1317
+ background: #28c840;
1318
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
1319
+ }
1320
+
1321
+ .devtools-titlebar-title {
1322
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1323
+ font-size: 0.75rem;
1324
+ font-weight: 500;
1325
+ color: var(--login-muted);
1326
+ letter-spacing: 0.02em;
1327
+ white-space: nowrap;
1328
+ overflow: hidden;
1329
+ text-overflow: ellipsis;
1330
+ }
1331
+
1332
+ .login-card {
1333
+ width: 100%;
1334
+ background-color: var(--login-panel);
1335
+ padding: var(--spacing-lg) var(--spacing-xl) var(--spacing-xl);
1336
+ border-radius: 0;
1337
+ box-shadow: none;
1338
+ }
1339
+
1340
+ .login-panel-toolbar {
1341
+ display: flex;
1342
+ align-items: center;
1343
+ gap: 6px;
1344
+ margin-bottom: var(--spacing-lg);
1345
+ padding-bottom: var(--spacing-sm);
1346
+ border-bottom: 1px solid var(--login-border);
1347
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1348
+ font-size: 0.6875rem;
1349
+ color: var(--login-muted);
1350
+ }
1351
+
1352
+ .login-panel-sep {
1353
+ opacity: 0.6;
1354
+ }
1355
+
1356
+ .login-panel-breadcrumb--accent {
1357
+ color: var(--login-accent);
1358
+ }
1359
+
1360
+ .login-header {
1361
+ text-align: left;
1362
+ margin-bottom: var(--spacing-lg);
1363
+ }
1364
+
1365
+ .login-title {
1366
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1367
+ font-size: 1.25rem;
1368
+ font-weight: 700;
1369
+ color: var(--login-text);
1370
+ margin-bottom: var(--spacing-xs);
1371
+ letter-spacing: -0.02em;
1372
+ }
1373
+
1374
+ .login-title-prompt {
1375
+ color: var(--login-cta);
1376
+ margin-right: 0.25em;
1377
+ user-select: none;
1378
+ }
1379
+
1380
+ .login-subtitle {
1381
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1382
+ font-size: 0.75rem;
1383
+ color: var(--login-muted);
1384
+ }
1385
+
1386
+ .login-prop {
1387
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1388
+ font-size: 0.8125rem;
1389
+ font-weight: 500;
1390
+ color: var(--login-accent);
1391
+ }
1392
+
1393
+ .login-page .form-label {
1394
+ color: var(--login-muted);
1395
+ }
1396
+
1397
+ .login-page .login-input,
1398
+ body.login-body .login-page input[type="text"],
1399
+ body.login-body .login-page input[type="password"] {
1400
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1401
+ font-size: 0.8125rem;
1402
+ color: var(--login-string);
1403
+ background-color: #0f172a;
1404
+ border: 1px solid var(--login-border);
1405
+ border-radius: 4px;
1406
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
1407
+ }
1408
+
1409
+ .login-page .login-input::placeholder,
1410
+ body.login-body .login-page input::placeholder {
1411
+ color: #64748b;
1412
+ }
1413
+
1414
+ .login-page .login-input:focus,
1415
+ body.login-body .login-page input:focus {
1416
+ outline: none;
1417
+ border-color: var(--login-accent);
1418
+ box-shadow: 0 0 0 2px rgba(125, 211, 252, 0.2);
1419
+ }
1420
+
1421
+ .login-actions {
1422
+ margin-bottom: 0;
1423
+ margin-top: var(--spacing-lg);
1424
+ }
1425
+
1426
+ .btn-devtools {
1427
+ display: inline-flex;
1428
+ align-items: center;
1429
+ justify-content: center;
1430
+ gap: 0.5rem;
1431
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1432
+ font-weight: 600;
1433
+ font-size: 0.875rem;
1434
+ background-color: var(--login-cta);
1435
+ color: #052e16;
1436
+ border: 1px solid #15803d;
1437
+ border-radius: 4px;
1438
+ cursor: pointer;
1439
+ transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
1440
+ }
1441
+
1442
+ .btn-devtools:hover:not(:disabled) {
1443
+ background-color: var(--login-cta-hover);
1444
+ border-color: #166534;
1445
+ color: #022c14;
1446
+ }
1447
+
1448
+ .btn-devtools:focus-visible {
1449
+ outline: 2px solid var(--login-accent);
1450
+ outline-offset: 2px;
1451
+ }
1452
+
1453
+ .btn-devtools-icon {
1454
+ flex-shrink: 0;
1455
+ opacity: 0.9;
1456
+ }
1457
+
1458
+ .login-page .btn-devtools .spinner {
1459
+ border-color: rgba(5, 46, 22, 0.35);
1460
+ border-top-color: #052e16;
1461
+ flex-shrink: 0;
1462
+ }
1463
+
1464
+ .login-error {
1465
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1466
+ font-size: 0.75rem;
1467
+ background-color: var(--login-error-bg);
1468
+ color: var(--login-error-fg);
1469
+ padding: var(--spacing-sm) var(--spacing-md);
1470
+ border-radius: 4px;
1471
+ border: 1px solid rgba(248, 113, 113, 0.35);
1472
+ margin-bottom: var(--spacing-md);
1473
+ display: none;
1474
+ }
1475
+
1476
+ .login-error.visible {
1477
+ display: block;
1478
+ }
1479
+
1480
+ .login-success {
1481
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
1482
+ font-size: 0.75rem;
1483
+ background-color: rgba(34, 197, 94, 0.15);
1484
+ color: #86efac;
1485
+ padding: var(--spacing-sm) var(--spacing-md);
1486
+ border-radius: 4px;
1487
+ border: 1px solid rgba(74, 222, 128, 0.35);
1488
+ margin-bottom: var(--spacing-md);
1489
+ }
1490
+
1491
+ @media (prefers-reduced-motion: reduce) {
1492
+ .login-page .login-input,
1493
+ .login-page .btn-devtools {
1494
+ transition: none;
1495
+ }
1496
+ }
1497
+
1498
+ /* ========================================
1499
+ 响应式设计
1500
+ ======================================== */
1501
+ @media (max-width: 768px) {
1502
+ :root {
1503
+ --spacing-lg: 1rem;
1504
+ --spacing-xl: 1.5rem;
1505
+ }
1506
+
1507
+ .navbar {
1508
+ height: 56px;
1509
+ }
1510
+
1511
+ .navbar-brand {
1512
+ font-size: 1.125rem;
1513
+ }
1514
+
1515
+ .navbar-nav {
1516
+ gap: var(--spacing-md);
1517
+ }
1518
+
1519
+ .page-content {
1520
+ padding-top: 72px;
1521
+ }
1522
+
1523
+ .container {
1524
+ padding: 0 var(--spacing-sm);
1525
+ }
1526
+
1527
+ .card {
1528
+ padding: var(--spacing-md);
1529
+ }
1530
+
1531
+ .btn {
1532
+ padding: 0.5rem 0.875rem;
1533
+ }
1534
+
1535
+ .login-card {
1536
+ padding: var(--spacing-lg);
1537
+ }
1538
+
1539
+ .login-title {
1540
+ font-size: 1.5rem;
1541
+ }
1542
+
1543
+ .toast-container {
1544
+ left: var(--spacing-sm);
1545
+ right: var(--spacing-sm);
1546
+ }
1547
+
1548
+ .toast {
1549
+ max-width: none;
1550
+ }
1551
+
1552
+ /* 隐藏部分导航项 */
1553
+ .navbar-nav .hide-mobile {
1554
+ display: none;
1555
+ }
1556
+ }
1557
+
1558
+ @media (max-width: 480px) {
1559
+ .login-page {
1560
+ padding: var(--spacing-sm);
1561
+ }
1562
+
1563
+ .btn-block-mobile {
1564
+ display: flex;
1565
+ width: 100%;
1566
+ }
1567
+ }