skill-base 2.0.3 → 2.0.6

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 (46) hide show
  1. package/README.md +189 -85
  2. package/bin/skill-base.js +33 -7
  3. package/package.json +3 -1
  4. package/src/cappy.js +416 -0
  5. package/src/database.js +11 -0
  6. package/src/index.js +87 -24
  7. package/src/middleware/auth.js +96 -32
  8. package/src/routes/auth.js +1 -1
  9. package/src/routes/skills.js +10 -5
  10. package/src/utils/zip.js +15 -4
  11. package/static/android-chrome-192x192.png +0 -0
  12. package/static/android-chrome-512x512.png +0 -0
  13. package/static/apple-touch-icon.png +0 -0
  14. package/static/assets/index-BgwubB87.css +1 -0
  15. package/static/assets/index-DBHCo8Mz.js +230 -0
  16. package/static/favicon-16x16.png +0 -0
  17. package/static/favicon-32x32.png +0 -0
  18. package/static/favicon.ico +0 -0
  19. package/static/favicon.svg +14 -0
  20. package/static/index.html +18 -248
  21. package/static/site.webmanifest +1 -0
  22. package/static/admin/users.html +0 -593
  23. package/static/cli-code.html +0 -203
  24. package/static/css/.gitkeep +0 -0
  25. package/static/css/style.css +0 -1567
  26. package/static/diff.html +0 -466
  27. package/static/file.html +0 -443
  28. package/static/js/.gitkeep +0 -0
  29. package/static/js/admin/users.js +0 -346
  30. package/static/js/app.js +0 -508
  31. package/static/js/auth.js +0 -151
  32. package/static/js/cli-code.js +0 -184
  33. package/static/js/collaborators.js +0 -283
  34. package/static/js/diff.js +0 -540
  35. package/static/js/file.js +0 -619
  36. package/static/js/i18n.js +0 -739
  37. package/static/js/index.js +0 -168
  38. package/static/js/publish.js +0 -718
  39. package/static/js/settings.js +0 -124
  40. package/static/js/setup.js +0 -157
  41. package/static/js/skill.js +0 -808
  42. package/static/login.html +0 -82
  43. package/static/publish.html +0 -459
  44. package/static/settings.html +0 -163
  45. package/static/setup.html +0 -101
  46. package/static/skill.html +0 -851
@@ -1,168 +0,0 @@
1
- /**
2
- * Skill Base - 列表页逻辑
3
- */
4
-
5
- /** 递增以丢弃过期的列表请求结果,避免乱序响应把界面刷回旧数据 */
6
- let skillsListLoadGen = 0;
7
-
8
- // 页面加载时初始化
9
- document.addEventListener('DOMContentLoaded', async () => {
10
- // 1. 检查登录状态
11
- const user = await checkAuth();
12
- if (!user) return;
13
-
14
- // 2. 渲染导航栏
15
- renderNavbar(user);
16
-
17
- // 3. 加载 Skill 列表
18
- await loadSkills();
19
-
20
- // 4. 绑定搜索事件(防抖 300ms)
21
- const searchInput = document.getElementById('searchInput');
22
- const clearBtn = document.getElementById('clearSearch');
23
-
24
- const debouncedSearch = debounce((query) => {
25
- loadSkills(query);
26
- }, 300);
27
-
28
- searchInput.addEventListener('input', (e) => {
29
- const query = e.target.value.trim();
30
- debouncedSearch(query);
31
-
32
- // 显示/隐藏清除按钮
33
- if (query) {
34
- clearBtn.classList.add('visible');
35
- } else {
36
- clearBtn.classList.remove('visible');
37
- }
38
- });
39
-
40
- // 清除搜索
41
- clearBtn.addEventListener('click', () => {
42
- searchInput.value = '';
43
- clearBtn.classList.remove('visible');
44
- loadSkills();
45
- searchInput.focus();
46
- });
47
- });
48
-
49
- /**
50
- * 加载 Skill 列表
51
- * @param {string} query - 搜索关键词
52
- */
53
- async function loadSkills(query = '') {
54
- const container = document.getElementById('skill-list');
55
- const gen = ++skillsListLoadGen;
56
-
57
- // 仅首屏容器为空时用骨架屏;搜索/刷新时保留当前列表,等数据到了再一次性替换,避免整块闪烁
58
- if (container.children.length === 0) {
59
- container.innerHTML = renderSkeletonCards(6);
60
- }
61
-
62
- try {
63
- const url = '/skills' + (query ? '?q=' + encodeURIComponent(query) : '');
64
- const data = await apiGet(url);
65
-
66
- if (gen !== skillsListLoadGen) return;
67
-
68
- const skills = data.skills || [];
69
-
70
- if (skills.length === 0) {
71
- container.innerHTML = renderEmptyState(query);
72
- return;
73
- }
74
-
75
- container.innerHTML = skills.map(skill => renderSkillCard(skill)).join('');
76
- } catch (error) {
77
- if (gen !== skillsListLoadGen) return;
78
- console.error('加载 Skill 列表失败:', error);
79
- showToast('加载失败: ' + error.message, 'error');
80
- container.innerHTML = renderEmptyState();
81
- }
82
- }
83
-
84
- /**
85
- * 渲染单个 Skill 卡片
86
- * @param {object} skill - Skill 数据
87
- * @returns {string} - 卡片 HTML 字符串
88
- */
89
- function renderSkillCard(skill) {
90
- // 截断描述到 100 字
91
- let description = skill.description || '暂无描述';
92
- if (description.length > 100) {
93
- description = description.substring(0, 100) + '...';
94
- }
95
-
96
- // 获取负责人名称(优先显示 name,没有则显示 username)
97
- const ownerName = skill.owner?.name || skill.owner?.username || '未知';
98
-
99
- // 格式化更新时间
100
- const updatedTime = formatDate(skill.updated_at);
101
-
102
- return `
103
- <a href="/skill.html?id=${encodeURIComponent(skill.id)}" class="skill-card">
104
- <div class="skill-card-header">
105
- <h3 class="skill-card-name">${escapeHtml(skill.name)}</h3>
106
- <span class="version-tag latest">${escapeHtml(skill.latest_version || '-')}</span>
107
- </div>
108
- <p class="skill-card-desc">${escapeHtml(description)}</p>
109
- <div class="skill-card-footer">
110
- <div class="skill-card-meta">
111
- <span class="skill-card-owner">
112
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
113
- <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
114
- <circle cx="12" cy="7" r="4"/>
115
- </svg>
116
- ${escapeHtml(ownerName)}
117
- </span>
118
- </div>
119
- <span>${updatedTime}</span>
120
- </div>
121
- </a>
122
- `;
123
- }
124
-
125
- /**
126
- * 渲染骨架屏 Loading 卡片
127
- * @param {number} count - 卡片数量
128
- * @returns {string} - 骨架屏 HTML
129
- */
130
- function renderSkeletonCards(count) {
131
- let html = '';
132
- for (let i = 0; i < count; i++) {
133
- html += `
134
- <div class="skeleton-card">
135
- <div class="skeleton skeleton-title"></div>
136
- <div class="skeleton skeleton-desc"></div>
137
- <div class="skeleton skeleton-desc-short"></div>
138
- <div class="skeleton skeleton-footer"></div>
139
- </div>
140
- `;
141
- }
142
- return html;
143
- }
144
-
145
- /**
146
- * 渲染空状态
147
- * @param {string} query - 搜索关键词
148
- * @returns {string} - 空状态 HTML
149
- */
150
- function renderEmptyState(query) {
151
- if (query) {
152
- return `
153
- <div class="empty-state" style="grid-column: 1 / -1;">
154
- <div class="empty-state-icon">🔍</div>
155
- <p class="empty-state-text">未找到包含 "${escapeHtml(query)}" 的 Skill</p>
156
- <p class="text-muted">试试其他关键词?</p>
157
- </div>
158
- `;
159
- }
160
-
161
- return `
162
- <div class="empty-state" style="grid-column: 1 / -1;">
163
- <div class="empty-state-icon">📦</div>
164
- <p class="empty-state-text">暂无 Skill,去发布第一个吧</p>
165
- <a href="/publish.html" class="btn btn-primary">发布 Skill</a>
166
- </div>
167
- `;
168
- }