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,851 @@
1
+ <!DOCTYPE html>
2
+ <html lang="">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title data-i18n="skill.title">Skill 详情 - Skill Base</title>
7
+ <link rel="stylesheet" href="/css/style.css">
8
+ <!-- highlight.js 样式 -->
9
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11.9.0/styles/github-dark.min.css">
10
+ <style>
11
+ /* 面包屑导航 */
12
+ .breadcrumb {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: var(--spacing-sm);
16
+ font-size: 0.875rem;
17
+ color: var(--text-secondary);
18
+ margin-bottom: var(--spacing-lg);
19
+ }
20
+
21
+ .breadcrumb a {
22
+ color: var(--text-secondary);
23
+ }
24
+
25
+ .breadcrumb a:hover {
26
+ color: var(--primary-color);
27
+ }
28
+
29
+ .breadcrumb-separator {
30
+ color: var(--text-muted);
31
+ }
32
+
33
+ /* Skill 信息区域 */
34
+ .skill-info {
35
+ background-color: var(--white);
36
+ border-radius: var(--radius);
37
+ box-shadow: var(--shadow);
38
+ padding: var(--spacing-lg);
39
+ margin-bottom: var(--spacing-lg);
40
+ }
41
+
42
+ .skill-header {
43
+ display: flex;
44
+ align-items: flex-start;
45
+ justify-content: space-between;
46
+ gap: var(--spacing-md);
47
+ margin-bottom: var(--spacing-md);
48
+ }
49
+
50
+ .skill-title {
51
+ font-size: 1.5rem;
52
+ font-weight: 700;
53
+ color: var(--text-color);
54
+ margin: 0;
55
+ }
56
+
57
+ .skill-desc {
58
+ color: var(--text-secondary);
59
+ margin-bottom: var(--spacing-md);
60
+ line-height: 1.6;
61
+ }
62
+
63
+ .skill-meta {
64
+ display: flex;
65
+ flex-wrap: wrap;
66
+ gap: var(--spacing-lg);
67
+ font-size: 0.875rem;
68
+ color: var(--text-secondary);
69
+ }
70
+
71
+ .skill-meta-item {
72
+ display: flex;
73
+ align-items: center;
74
+ gap: var(--spacing-xs);
75
+ }
76
+
77
+ /* 版本选择器和操作按钮 */
78
+ .skill-actions {
79
+ display: flex;
80
+ flex-wrap: wrap;
81
+ align-items: center;
82
+ gap: var(--spacing-md);
83
+ margin-top: var(--spacing-lg);
84
+ padding-top: var(--spacing-md);
85
+ border-top: 1px solid var(--border-color);
86
+ }
87
+
88
+ .version-select {
89
+ min-width: 200px;
90
+ }
91
+
92
+ /* 左右分栏布局(minmax(0,1fr) 防止右侧被长内容撑开整页) */
93
+ .skill-content {
94
+ display: grid;
95
+ grid-template-columns: 280px minmax(0, 1fr);
96
+ gap: var(--spacing-lg);
97
+ margin-bottom: var(--spacing-lg);
98
+ }
99
+
100
+ /* 文件树面板 */
101
+ .file-tree-panel {
102
+ background-color: var(--white);
103
+ border-radius: var(--radius);
104
+ box-shadow: var(--shadow);
105
+ padding: var(--spacing-md);
106
+ max-height: calc(100vh - 300px);
107
+ overflow-y: auto;
108
+ }
109
+
110
+ .file-tree-panel-title {
111
+ font-size: 0.875rem;
112
+ font-weight: 600;
113
+ color: var(--text-color);
114
+ margin-bottom: var(--spacing-md);
115
+ padding-bottom: var(--spacing-sm);
116
+ border-bottom: 1px solid var(--border-color);
117
+ }
118
+
119
+ /* 文件预览面板 */
120
+ .file-preview-panel {
121
+ background-color: var(--white);
122
+ border-radius: var(--radius);
123
+ box-shadow: var(--shadow);
124
+ min-height: 400px;
125
+ max-height: 900px;
126
+ overflow-y: auto;
127
+ min-width: 0;
128
+ display: flex;
129
+ flex-direction: column;
130
+ }
131
+
132
+ .file-preview-header {
133
+ padding: var(--spacing-md) var(--spacing-lg);
134
+ border-bottom: 1px solid var(--border-color);
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: space-between;
138
+ gap: var(--spacing-md);
139
+ flex-wrap: wrap;
140
+ }
141
+
142
+ .file-preview-path {
143
+ flex: 1;
144
+ min-width: 0;
145
+ font-family: 'SF Mono', Monaco, 'Courier New', monospace;
146
+ font-size: 0.875rem;
147
+ color: var(--text-secondary);
148
+ overflow: hidden;
149
+ text-overflow: ellipsis;
150
+ white-space: nowrap;
151
+ }
152
+
153
+ .file-preview-md-actions {
154
+ flex-shrink: 0;
155
+ }
156
+
157
+ .md-view-toggle {
158
+ display: inline-flex;
159
+ border: 1px solid var(--border-color);
160
+ border-radius: var(--radius-sm);
161
+ overflow: hidden;
162
+ }
163
+
164
+ .md-view-btn {
165
+ padding: 0.25rem 0.625rem;
166
+ font-size: 0.8125rem;
167
+ border: none;
168
+ background: var(--bg-color);
169
+ color: var(--text-secondary);
170
+ cursor: pointer;
171
+ }
172
+
173
+ .md-view-btn + .md-view-btn {
174
+ border-left: 1px solid var(--border-color);
175
+ }
176
+
177
+ .md-view-btn.is-active {
178
+ background: var(--white);
179
+ color: var(--text-color);
180
+ font-weight: 500;
181
+ }
182
+
183
+ .file-preview-content {
184
+ flex: 1;
185
+ min-width: 0;
186
+ padding: var(--spacing-lg);
187
+ overflow: auto;
188
+ overflow-wrap: break-word;
189
+ word-break: break-word;
190
+ }
191
+
192
+ .file-preview-content pre {
193
+ margin: 0;
194
+ padding: var(--spacing-md);
195
+ background-color: var(--bg-color);
196
+ border-radius: var(--radius);
197
+ overflow-x: hidden;
198
+ white-space: pre-wrap;
199
+ word-break: break-word;
200
+ overflow-wrap: anywhere;
201
+ }
202
+
203
+ .file-preview-content code {
204
+ font-family: 'SF Mono', Monaco, 'Courier New', monospace;
205
+ font-size: 0.8125rem;
206
+ line-height: 1.6;
207
+ }
208
+
209
+ .file-preview-content > pre code,
210
+ .file-preview-content pre code {
211
+ white-space: pre-wrap;
212
+ word-break: break-word;
213
+ overflow-wrap: anywhere;
214
+ }
215
+
216
+ /* Markdown 预览样式 */
217
+ .markdown-body {
218
+ line-height: 1.8;
219
+ max-width: 100%;
220
+ overflow-wrap: break-word;
221
+ word-break: break-word;
222
+ }
223
+
224
+ .markdown-body pre {
225
+ white-space: pre-wrap;
226
+ word-break: break-word;
227
+ overflow-wrap: anywhere;
228
+ overflow-x: hidden;
229
+ max-width: 100%;
230
+ }
231
+
232
+ .markdown-body pre code {
233
+ white-space: pre-wrap;
234
+ word-break: break-word;
235
+ overflow-wrap: anywhere;
236
+ }
237
+
238
+ /* 宽表格在面板内横向滚动,不撑开栅格 */
239
+ .markdown-body .md-table-wrap {
240
+ max-width: 100%;
241
+ overflow-x: auto;
242
+ }
243
+
244
+ .markdown-body .md-table-wrap table {
245
+ width: max-content;
246
+ max-width: none;
247
+ }
248
+
249
+ .markdown-body h1,
250
+ .markdown-body h2,
251
+ .markdown-body h3,
252
+ .markdown-body h4 {
253
+ margin-top: 1.5em;
254
+ margin-bottom: 0.5em;
255
+ font-weight: 600;
256
+ }
257
+
258
+ .markdown-body h1 { font-size: 1.5rem; }
259
+ .markdown-body h2 { font-size: 1.25rem; }
260
+ .markdown-body h3 { font-size: 1.125rem; }
261
+
262
+ .markdown-body p {
263
+ margin-bottom: 1em;
264
+ }
265
+
266
+ .markdown-body ul,
267
+ .markdown-body ol {
268
+ padding-left: 2em;
269
+ margin-bottom: 1em;
270
+ }
271
+
272
+ .markdown-body li {
273
+ list-style: disc;
274
+ margin-bottom: 0.25em;
275
+ }
276
+
277
+ .markdown-body ol li {
278
+ list-style: decimal;
279
+ }
280
+
281
+ .markdown-body code {
282
+ background-color: var(--bg-color);
283
+ padding: 0.125em 0.375em;
284
+ border-radius: var(--radius-sm);
285
+ font-size: 0.875em;
286
+ }
287
+
288
+ .markdown-body pre code {
289
+ background: none;
290
+ padding: 0;
291
+ }
292
+
293
+ .markdown-body blockquote {
294
+ border-left: 4px solid var(--border-color);
295
+ padding-left: 1em;
296
+ color: var(--text-secondary);
297
+ margin: 1em 0;
298
+ }
299
+
300
+ .markdown-body table {
301
+ width: 100%;
302
+ border-collapse: collapse;
303
+ margin: 1em 0;
304
+ }
305
+
306
+ .markdown-body th,
307
+ .markdown-body td {
308
+ border: 1px solid var(--border-color);
309
+ padding: 0.5em 1em;
310
+ text-align: left;
311
+ }
312
+
313
+ .markdown-body th {
314
+ background-color: var(--bg-color);
315
+ }
316
+
317
+ /* 版本历史 */
318
+ .version-history {
319
+ margin-top: 2em;
320
+ background-color: var(--white);
321
+ border-radius: var(--radius);
322
+ box-shadow: var(--shadow);
323
+ }
324
+
325
+ .version-history-header {
326
+ padding: var(--spacing-md) var(--spacing-lg);
327
+ border-bottom: 1px solid var(--border-color);
328
+ display: flex;
329
+ align-items: center;
330
+ justify-content: space-between;
331
+ cursor: pointer;
332
+ }
333
+
334
+ .version-history-header:hover {
335
+ background-color: var(--bg-color);
336
+ }
337
+
338
+ .version-history-title {
339
+ font-size: 1rem;
340
+ font-weight: 600;
341
+ color: var(--text-color);
342
+ display: flex;
343
+ align-items: center;
344
+ gap: var(--spacing-sm);
345
+ }
346
+
347
+ .version-history-toggle {
348
+ color: var(--text-muted);
349
+ transition: var(--transition);
350
+ }
351
+
352
+ .version-history.collapsed .version-history-toggle {
353
+ transform: rotate(-90deg);
354
+ }
355
+
356
+ .version-history-list {
357
+ padding: 0;
358
+ max-height: 400px;
359
+ overflow-y: auto;
360
+ }
361
+
362
+ .version-history.collapsed .version-history-list {
363
+ display: none;
364
+ }
365
+
366
+ .version-item {
367
+ padding: var(--spacing-md) var(--spacing-lg);
368
+ border-bottom: 1px solid var(--border-color);
369
+ display: flex;
370
+ align-items: flex-start;
371
+ gap: var(--spacing-md);
372
+ }
373
+
374
+ .version-item:last-child {
375
+ border-bottom: none;
376
+ }
377
+
378
+ .version-item:hover {
379
+ background-color: var(--bg-color);
380
+ }
381
+
382
+ .version-item-tag {
383
+ flex-shrink: 0;
384
+ }
385
+
386
+ .version-item-info {
387
+ flex: 1;
388
+ min-width: 0;
389
+ }
390
+
391
+ .version-item-changelog {
392
+ font-size: 0.875rem;
393
+ color: var(--text-color);
394
+ margin-bottom: var(--spacing-xs);
395
+ }
396
+
397
+ .version-item-meta {
398
+ font-size: 0.75rem;
399
+ color: var(--text-muted);
400
+ display: flex;
401
+ gap: var(--spacing-md);
402
+ }
403
+
404
+ /* 空状态 */
405
+ .empty-preview {
406
+ display: flex;
407
+ flex-direction: column;
408
+ align-items: center;
409
+ justify-content: center;
410
+ height: 100%;
411
+ min-height: 300px;
412
+ color: var(--text-muted);
413
+ }
414
+
415
+ .empty-preview-icon {
416
+ font-size: 3rem;
417
+ margin-bottom: var(--spacing-md);
418
+ opacity: 0.5;
419
+ }
420
+
421
+ /* Loading */
422
+ .loading-content {
423
+ display: flex;
424
+ align-items: center;
425
+ justify-content: center;
426
+ min-height: 200px;
427
+ }
428
+
429
+ /* 二进制文件提示 */
430
+ .binary-notice {
431
+ text-align: center;
432
+ padding: var(--spacing-xl);
433
+ color: var(--text-secondary);
434
+ }
435
+
436
+ .binary-notice-icon {
437
+ font-size: 3rem;
438
+ margin-bottom: var(--spacing-md);
439
+ }
440
+
441
+ /* 协作者面板 */
442
+ .collaborators-panel {
443
+ margin-top: var(--spacing-lg);
444
+ padding: var(--spacing-lg);
445
+ background-color: var(--white);
446
+ border-radius: var(--radius);
447
+ box-shadow: var(--shadow);
448
+ }
449
+
450
+ .collaborators-panel .panel-header {
451
+ display: flex;
452
+ align-items: center;
453
+ justify-content: space-between;
454
+ margin-bottom: var(--spacing-md);
455
+ }
456
+
457
+ .collaborators-panel .panel-header h3 {
458
+ font-size: 1rem;
459
+ font-weight: 600;
460
+ margin: 0;
461
+ }
462
+
463
+ .collaborators-list {
464
+ display: flex;
465
+ flex-direction: column;
466
+ gap: var(--spacing-sm);
467
+ }
468
+
469
+ .collaborator-item {
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: space-between;
473
+ padding: var(--spacing-sm) var(--spacing-md);
474
+ background-color: var(--bg-color);
475
+ border-radius: var(--radius-sm, 4px);
476
+ }
477
+
478
+ .collaborator-info {
479
+ display: flex;
480
+ align-items: center;
481
+ gap: var(--spacing-sm);
482
+ }
483
+
484
+ .collaborator-role {
485
+ font-size: 0.75rem;
486
+ padding: 2px 8px;
487
+ border-radius: 10px;
488
+ background-color: var(--primary-color);
489
+ color: var(--white);
490
+ font-weight: 500;
491
+ }
492
+
493
+ .collaborator-role.owner {
494
+ background-color: #f59e0b;
495
+ }
496
+
497
+ .danger-zone {
498
+ margin-top: var(--spacing-lg);
499
+ padding-top: var(--spacing-lg);
500
+ border-top: 1px solid var(--border-color);
501
+ }
502
+
503
+ .btn-danger {
504
+ background-color: #ef4444;
505
+ color: white;
506
+ border: none;
507
+ padding: 6px 16px;
508
+ border-radius: var(--radius-sm, 4px);
509
+ cursor: pointer;
510
+ }
511
+
512
+ .btn-danger:hover {
513
+ background-color: #dc2626;
514
+ }
515
+
516
+ /* 弹窗样式 */
517
+ .modal {
518
+ position: fixed;
519
+ top: 0;
520
+ left: 0;
521
+ right: 0;
522
+ bottom: 0;
523
+ z-index: 1000;
524
+ display: flex;
525
+ align-items: center;
526
+ justify-content: center;
527
+ }
528
+
529
+ .modal-overlay {
530
+ position: absolute;
531
+ top: 0;
532
+ left: 0;
533
+ right: 0;
534
+ bottom: 0;
535
+ background-color: rgba(0, 0, 0, 0.5);
536
+ }
537
+
538
+ .modal-content {
539
+ position: relative;
540
+ background-color: var(--white);
541
+ border-radius: var(--radius);
542
+ box-shadow: var(--shadow-lg);
543
+ width: 90%;
544
+ max-width: 420px;
545
+ padding: var(--spacing-lg);
546
+ }
547
+
548
+ .modal-header {
549
+ display: flex;
550
+ align-items: center;
551
+ justify-content: space-between;
552
+ margin-bottom: var(--spacing-md);
553
+ }
554
+
555
+ .modal-header h3 {
556
+ margin: 0;
557
+ font-size: 1.125rem;
558
+ }
559
+
560
+ .modal-close {
561
+ background: none;
562
+ border: none;
563
+ font-size: 1.5rem;
564
+ cursor: pointer;
565
+ color: var(--text-secondary);
566
+ line-height: 1;
567
+ }
568
+
569
+ .modal-body {
570
+ margin-bottom: var(--spacing-lg);
571
+ }
572
+
573
+ .modal-footer {
574
+ display: flex;
575
+ justify-content: flex-end;
576
+ gap: var(--spacing-sm);
577
+ }
578
+
579
+ .form-group {
580
+ margin-bottom: var(--spacing-md);
581
+ }
582
+
583
+ .form-group label {
584
+ display: block;
585
+ margin-bottom: var(--spacing-xs);
586
+ font-size: 0.875rem;
587
+ font-weight: 500;
588
+ }
589
+
590
+ .form-input {
591
+ width: 100%;
592
+ padding: 8px 12px;
593
+ border: 1px solid var(--border-color);
594
+ border-radius: var(--radius-sm, 4px);
595
+ font-size: 0.875rem;
596
+ background-color: var(--bg-color);
597
+ color: var(--text-color);
598
+ box-sizing: border-box;
599
+ }
600
+
601
+ .warning-text {
602
+ color: #ef4444;
603
+ font-size: 0.875rem;
604
+ margin-bottom: var(--spacing-md);
605
+ }
606
+
607
+ /* 协作者 username 小字 */
608
+ .collaborator-username {
609
+ color: var(--text-muted);
610
+ font-size: 0.8125rem;
611
+ margin-left: 4px;
612
+ }
613
+
614
+ /* 联想搜索下拉 */
615
+ .suggestions-container {
616
+ position: relative;
617
+ }
618
+
619
+ .suggestions-dropdown {
620
+ position: absolute;
621
+ top: 100%;
622
+ left: 0;
623
+ right: 0;
624
+ background: var(--white);
625
+ border: 1px solid var(--border-color);
626
+ border-top: none;
627
+ border-radius: 0 0 var(--radius-sm, 4px) var(--radius-sm, 4px);
628
+ max-height: 200px;
629
+ overflow-y: auto;
630
+ z-index: 10;
631
+ display: none;
632
+ }
633
+
634
+ .suggestions-dropdown.is-open {
635
+ display: block;
636
+ }
637
+
638
+ .suggestion-item {
639
+ padding: 8px 12px;
640
+ cursor: pointer;
641
+ font-size: 0.875rem;
642
+ display: flex;
643
+ align-items: center;
644
+ gap: 8px;
645
+ }
646
+
647
+ .suggestion-item:hover,
648
+ .suggestion-item.is-active {
649
+ background-color: var(--bg-color);
650
+ }
651
+
652
+ .suggestion-item-name {
653
+ color: var(--text-color);
654
+ font-weight: 500;
655
+ }
656
+
657
+ .suggestion-item-username {
658
+ color: var(--text-muted);
659
+ font-size: 0.8125rem;
660
+ }
661
+
662
+ .suggestion-empty {
663
+ padding: 8px 12px;
664
+ font-size: 0.875rem;
665
+ color: var(--text-muted);
666
+ text-align: center;
667
+ }
668
+
669
+ @media (max-width: 768px) {
670
+ .skill-content {
671
+ grid-template-columns: 1fr;
672
+ }
673
+
674
+ .file-tree-panel {
675
+ max-height: 300px;
676
+ }
677
+
678
+ .skill-header {
679
+ flex-direction: column;
680
+ }
681
+
682
+ .skill-actions {
683
+ flex-direction: column;
684
+ align-items: stretch;
685
+ }
686
+
687
+ .version-select {
688
+ width: 100%;
689
+ }
690
+ }
691
+ </style>
692
+ </head>
693
+ <body class="app-devtools">
694
+ <!-- 导航栏 -->
695
+ <nav class="navbar">
696
+ <div class="container">
697
+ <a href="/" class="navbar-brand">
698
+ <svg class="navbar-brand-icon" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
699
+ <span>Skill Base</span>
700
+ </a>
701
+ <div class="navbar-nav">
702
+ <a href="/" data-i18n="nav.home">首页</a>
703
+ <a href="/publish.html" class="hide-mobile" data-i18n="nav.publish">发布</a>
704
+ </div>
705
+ </div>
706
+ </nav>
707
+
708
+ <!-- 页面内容 -->
709
+ <main class="page-content">
710
+ <div class="container">
711
+ <!-- 面包屑导航 -->
712
+ <nav class="breadcrumb">
713
+ <a href="/" data-i18n="skill.breadcrumbHome">首页</a>
714
+ <span class="breadcrumb-separator">›</span>
715
+ <span id="breadcrumb-name" data-i18n="state.loading">加载中...</span>
716
+ </nav>
717
+
718
+ <!-- Skill 基本信息 -->
719
+ <section class="skill-info" id="skill-info">
720
+ <div class="loading-content">
721
+ <div class="spinner"></div>
722
+ </div>
723
+ </section>
724
+
725
+ <!-- 左右分栏:目录树 + 文件预览 -->
726
+ <section class="skill-content">
727
+ <!-- 文件树面板 -->
728
+ <div class="file-tree-panel">
729
+ <div class="file-tree-panel-title" data-i18n="skill.fileDir">文件目录</div>
730
+ <div id="file-tree" class="file-tree">
731
+ <div class="loading-content">
732
+ <div class="spinner spinner-sm"></div>
733
+ </div>
734
+ </div>
735
+ </div>
736
+
737
+ <!-- 文件预览面板 -->
738
+ <div class="file-preview-panel">
739
+ <div class="file-preview-header">
740
+ <span id="file-preview-path" class="file-preview-path" data-i18n="skill.selectFile">选择文件以预览</span>
741
+ <div id="file-preview-md-actions" class="file-preview-md-actions" hidden>
742
+ <div class="md-view-toggle" role="group" aria-label="Markdown 显示方式">
743
+ <button type="button" id="md-view-render" class="md-view-btn is-active" data-i18n="skill.htmlPreview">HTML 预览</button>
744
+ <button type="button" id="md-view-source" class="md-view-btn" data-i18n="skill.mdSource">Markdown 源码</button>
745
+ </div>
746
+ </div>
747
+ </div>
748
+ <div id="file-content" class="file-preview-content">
749
+ <div class="empty-preview">
750
+ <div class="empty-preview-icon">📄</div>
751
+ <p data-i18n="skill.clickFile">点击左侧文件查看内容</p>
752
+ </div>
753
+ </div>
754
+ </div>
755
+ </section>
756
+
757
+ <!-- 协作者管理 -->
758
+ <div id="collaborators-panel" class="collaborators-panel" style="display:none;">
759
+ <div class="panel-header">
760
+ <h3 data-i18n="skill.team">管理团队</h3>
761
+ <button id="add-collaborator-btn" class="btn btn-primary btn-sm" style="display:none;" data-i18n="skill.addCollaborator">+ 添加协作者</button>
762
+ </div>
763
+ <div id="collaborators-list" class="collaborators-list">
764
+ <!-- 由 JS 动态渲染 -->
765
+ </div>
766
+ <div id="skill-danger-zone" class="danger-zone" style="display:none;">
767
+ <button id="delete-skill-btn" class="btn btn-danger btn-sm" data-i18n="skill.deleteSkill">删除 Skill</button>
768
+ </div>
769
+ </div>
770
+
771
+ <!-- 版本历史 -->
772
+ <section class="version-history" id="version-history">
773
+ <div class="version-history-header" onclick="toggleVersionHistory()">
774
+ <h3 class="version-history-title">
775
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
776
+ <circle cx="12" cy="12" r="10"/>
777
+ <polyline points="12 6 12 12 16 14"/>
778
+ </svg>
779
+ <span data-i18n="skill.versionHistory">版本历史</span>
780
+ </h3>
781
+ <span class="version-history-toggle">
782
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
783
+ <polyline points="6 9 12 15 18 9"/>
784
+ </svg>
785
+ </span>
786
+ </div>
787
+ <div class="version-history-list" id="version-list">
788
+ <div class="loading-content">
789
+ <div class="spinner spinner-sm"></div>
790
+ </div>
791
+ </div>
792
+ </section>
793
+ </div>
794
+ </main>
795
+
796
+ <!-- 添加协作者弹窗 -->
797
+ <div id="add-collaborator-modal" class="modal" style="display:none;">
798
+ <div class="modal-overlay"></div>
799
+ <div class="modal-content">
800
+ <div class="modal-header">
801
+ <h3 data-i18n="collab.modal">添加协作者</h3>
802
+ <button class="modal-close" onclick="closeCollaboratorModal()">&times;</button>
803
+ </div>
804
+ <div class="modal-body">
805
+ <div class="form-group suggestions-container">
806
+ <label data-i18n="collab.usernameLabel">用户名</label>
807
+ <input type="text" id="collaborator-username" data-i18n-placeholder="collab.usernamePlaceholder" placeholder="输入用户名" class="form-input" autocomplete="off">
808
+ <div id="user-suggestions" class="suggestions-dropdown"></div>
809
+ </div>
810
+ </div>
811
+ <div class="modal-footer">
812
+ <button class="btn btn-secondary" onclick="closeCollaboratorModal()" data-i18n="btn.cancel">取消</button>
813
+ <button class="btn btn-primary" onclick="submitAddCollaborator()" data-i18n="btn.add">添加</button>
814
+ </div>
815
+ </div>
816
+ </div>
817
+
818
+ <!-- 删除 Skill 确认弹窗 -->
819
+ <div id="delete-skill-modal" class="modal" style="display:none;">
820
+ <div class="modal-overlay"></div>
821
+ <div class="modal-content">
822
+ <div class="modal-header">
823
+ <h3 data-i18n="collab.deleteModal">确认删除</h3>
824
+ <button class="modal-close" onclick="closeDeleteModal()">&times;</button>
825
+ </div>
826
+ <div class="modal-body">
827
+ <p class="warning-text" data-i18n="collab.deleteWarning">⚠️ 此操作不可恢复!将删除该 Skill 的所有版本和数据。</p>
828
+ <div class="form-group">
829
+ <label data-i18n="collab.deleteLabel">请输入 Skill ID 确认删除:</label>
830
+ <input type="text" id="delete-confirm-input" placeholder="" class="form-input">
831
+ </div>
832
+ </div>
833
+ <div class="modal-footer">
834
+ <button class="btn btn-secondary" onclick="closeDeleteModal()" data-i18n="btn.cancel">取消</button>
835
+ <button class="btn btn-danger" onclick="submitDeleteSkill()" data-i18n="collab.deleteConfirmBtn">确认删除</button>
836
+ </div>
837
+ </div>
838
+ </div>
839
+
840
+ <!-- CDN 库 -->
841
+ <script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
842
+ <script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/marked.min.js"></script>
843
+ <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js"></script>
844
+
845
+ <!-- 引入 JS -->
846
+ <script src="/js/i18n.js"></script>
847
+ <script src="/js/app.js"></script>
848
+ <script src="/js/skill.js"></script>
849
+ <script src="/js/collaborators.js"></script>
850
+ </body>
851
+ </html>