skill-base 2.0.4 → 2.0.7
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.
- package/README.md +177 -115
- package/bin/skill-base.js +29 -3
- package/package.json +4 -1
- package/src/cappy.js +416 -0
- package/src/database.js +11 -0
- package/src/index.js +125 -25
- package/src/middleware/auth.js +96 -32
- package/src/routes/auth.js +1 -1
- package/src/routes/skills.js +10 -5
- package/src/utils/zip.js +15 -4
- package/static/android-chrome-192x192.png +0 -0
- package/static/android-chrome-512x512.png +0 -0
- package/static/apple-touch-icon.png +0 -0
- package/static/assets/index-BkwByEEp.css +1 -0
- package/static/assets/index-CB4Diul3.js +209 -0
- package/static/favicon-16x16.png +0 -0
- package/static/favicon-32x32.png +0 -0
- package/static/favicon.ico +0 -0
- package/static/favicon.svg +14 -0
- package/static/index.html +18 -248
- package/static/site.webmanifest +1 -0
- package/static/admin/users.html +0 -593
- package/static/cli-code.html +0 -203
- package/static/css/.gitkeep +0 -0
- package/static/css/style.css +0 -1567
- package/static/diff.html +0 -466
- package/static/file.html +0 -443
- package/static/js/.gitkeep +0 -0
- package/static/js/admin/users.js +0 -346
- package/static/js/app.js +0 -508
- package/static/js/auth.js +0 -151
- package/static/js/cli-code.js +0 -184
- package/static/js/collaborators.js +0 -283
- package/static/js/diff.js +0 -540
- package/static/js/file.js +0 -619
- package/static/js/i18n.js +0 -739
- package/static/js/index.js +0 -168
- package/static/js/publish.js +0 -718
- package/static/js/settings.js +0 -124
- package/static/js/setup.js +0 -157
- package/static/js/skill.js +0 -808
- package/static/login.html +0 -82
- package/static/publish.html +0 -459
- package/static/settings.html +0 -163
- package/static/setup.html +0 -101
- package/static/skill.html +0 -851
package/static/js/index.js
DELETED
|
@@ -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
|
-
}
|