mdk-skills 2.2.16 → 2.2.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdk-skills",
3
- "version": "2.2.16",
3
+ "version": "2.2.18",
4
4
  "description": "mdk-engineer - 沉稳靠谱的前端开发助手 Claude Skills 配置包,一键注入 .claude/ 技能目录和 CLAUDE.md 人设配置",
5
5
  "author": "XiaoMa",
6
6
  "license": "MIT",
@@ -149,6 +149,39 @@ body {
149
149
  transition: opacity 0.2s;
150
150
  }
151
151
 
152
+ /* ---------- 手搓折叠 ---------- */
153
+ .readme-fold {
154
+ margin-bottom: 20px;
155
+ border: 1px solid #e5e7eb;
156
+ border-radius: 6px;
157
+ overflow: hidden;
158
+ }
159
+ .fold-header {
160
+ display: flex;
161
+ align-items: center;
162
+ gap: 6px;
163
+ padding: 10px 16px;
164
+ font-size: 14px;
165
+ font-weight: 600;
166
+ background: #fafafa;
167
+ cursor: pointer;
168
+ user-select: none;
169
+ }
170
+ .fold-header:hover {
171
+ background: #f0f0f0;
172
+ }
173
+ .fold-arrow {
174
+ font-size: 11px;
175
+ transition: transform 0.2s;
176
+ color: #999;
177
+ }
178
+ .fold-arrow.open {
179
+ transform: rotate(90deg);
180
+ }
181
+ .fold-body {
182
+ padding: 0 16px 16px;
183
+ }
184
+
152
185
  .markdown-content pre:hover .copy-btn {
153
186
  opacity: 1;
154
187
  }
@@ -1,16 +1,22 @@
1
1
  <template>
2
2
  <div class="dashboard">
3
3
  <!-- 仓库 README -->
4
- <n-collapse v-if="readmeContent" :default-expanded-names="['readme']" class="readme-collapse" :animated="false">
5
- <n-collapse-item title="仓库说明" name="readme">
4
+ <div class="readme-fold" v-if="readmeContent">
5
+ <div class="fold-header" @click="readmeOpen = !readmeOpen">
6
+ <span class="fold-arrow" :class="{ open: readmeOpen }">▶</span>
7
+ 仓库说明
8
+ </div>
9
+ <div class="fold-body" v-show="readmeOpen">
6
10
  <div class="markdown-content" v-html="renderedReadme" />
7
- </n-collapse-item>
8
- </n-collapse>
11
+ </div>
12
+ </div>
9
13
 
10
14
  <div class="page-header">
11
15
  <h2>技能列表</h2>
12
16
  <n-button size="small" @click="loadSkills">
13
- <template #icon><n-icon><RefreshOutline /></n-icon></template>
17
+ <template #icon
18
+ ><n-icon><RefreshOutline /></n-icon
19
+ ></template>
14
20
  刷新
15
21
  </n-button>
16
22
  </div>
@@ -38,14 +44,18 @@
38
44
  v-model:show="detailVisible"
39
45
  :title="detailSkill?.name || '技能详情'"
40
46
  preset="card"
41
- style="width: 720px;"
47
+ style="width: 720px"
42
48
  content-style="max-height: 65vh; overflow-y: auto; padding: 16px 24px; background: #fff;"
43
49
  :mask-closable="true"
44
50
  >
45
51
  <div v-if="detailLoading" class="detail-status">
46
52
  <n-spin />
47
53
  </div>
48
- <div v-else-if="detailContent" class="markdown-content" v-html="renderedDetail" />
54
+ <div
55
+ v-else-if="detailContent"
56
+ class="markdown-content"
57
+ v-html="renderedDetail"
58
+ />
49
59
  <n-empty v-else description="该技能没有 SKILL.md 文档" />
50
60
  </n-modal>
51
61
  </div>
@@ -74,8 +84,11 @@ marked.use({
74
84
  return `<pre><button class="copy-btn" onclick="navigator.clipboard.writeText(this.parentNode.querySelector('code').textContent);this.textContent='已复制';setTimeout(()=>this.textContent='复制',1500)">复制</button><code class="hljs language-${language}">${highlighted}</code></pre>`;
75
85
  },
76
86
  link({ href, text }) {
77
- const isExternal = href && (href.startsWith("http://") || href.startsWith("https://"));
78
- const target = isExternal ? ' target="_blank" rel="noopener noreferrer"' : "";
87
+ const isExternal =
88
+ href && (href.startsWith("http://") || href.startsWith("https://"));
89
+ const target = isExternal
90
+ ? ' target="_blank" rel="noopener noreferrer"'
91
+ : "";
79
92
  return `<a href="${href}"${target}>${text}</a>`;
80
93
  },
81
94
  },
@@ -88,6 +101,7 @@ const loading = ref(false);
88
101
  // README
89
102
  const readmeContent = ref(null);
90
103
  const renderedReadme = ref("");
104
+ const readmeOpen = ref(true);
91
105
 
92
106
  // 详情弹窗
93
107
  const detailVisible = ref(false);
@@ -128,8 +142,8 @@ async function loadReadme() {
128
142
  try {
129
143
  const res = await getReadme();
130
144
  if (res.content) {
131
- readmeContent.value = res.content;
132
145
  renderedReadme.value = renderMd(res.content);
146
+ readmeContent.value = res.content;
133
147
  }
134
148
  } catch {
135
149
  // 静默失败
@@ -189,13 +203,9 @@ onUnmounted(() => document.removeEventListener("visibilitychange", onFocus));
189
203
  font-weight: 600;
190
204
  }
191
205
 
192
- .readme-collapse {
193
- margin-bottom: 20px;
194
- }
195
-
196
206
  .detail-status {
197
207
  display: flex;
198
208
  justify-content: center;
199
209
  padding: 40px 0;
200
210
  }
201
- </style>
211
+ </style>
@@ -1,16 +1,27 @@
1
1
  <template>
2
2
  <div class="scene-switch">
3
3
  <!-- 技能说明文档 -->
4
- <n-collapse v-if="skillsReadmeContent" :default-expanded-names="['skills-readme']" class="readme-collapse" :animated="false">
5
- <n-collapse-item title="技能说明" name="skills-readme">
4
+ <div class="readme-fold" v-if="skillsReadmeContent">
5
+ <div class="fold-header" @click="skillsReadmeOpen = !skillsReadmeOpen">
6
+ <span class="fold-arrow" :class="{ open: skillsReadmeOpen }">▶</span>
7
+ 技能说明
8
+ </div>
9
+ <div class="fold-body" v-show="skillsReadmeOpen">
6
10
  <div class="markdown-content" v-html="renderedSkillsReadme" />
7
- </n-collapse-item>
8
- </n-collapse>
11
+ </div>
12
+ </div>
9
13
 
10
14
  <div class="page-header">
11
15
  <h2>场景切换</h2>
12
- <n-button v-if="!readonly" size="small" type="primary" @click="openCreate">
13
- <template #icon><n-icon><AddOutline /></n-icon></template>
16
+ <n-button
17
+ v-if="!readonly"
18
+ size="small"
19
+ type="primary"
20
+ @click="openCreate"
21
+ >
22
+ <template #icon
23
+ ><n-icon><AddOutline /></n-icon
24
+ ></template>
14
25
  新建场景
15
26
  </n-button>
16
27
  </div>
@@ -26,9 +37,16 @@
26
37
  size="small"
27
38
  >
28
39
  <template #header-extra>
29
- <n-space v-if="!readonly && profile.id !== 'custom' && profile.skills !== null" :size="4">
40
+ <n-space
41
+ v-if="
42
+ !readonly && profile.id !== 'custom' && profile.skills !== null
43
+ "
44
+ :size="4"
45
+ >
30
46
  <n-button size="tiny" quaternary @click="openEdit(profile)">
31
- <template #icon><n-icon size="16"><PencilOutline /></n-icon></template>
47
+ <template #icon
48
+ ><n-icon size="16"><PencilOutline /></n-icon
49
+ ></template>
32
50
  </n-button>
33
51
  <n-popconfirm
34
52
  :negative-text="'取消'"
@@ -37,7 +55,9 @@
37
55
  >
38
56
  <template #trigger>
39
57
  <n-button size="tiny" quaternary>
40
- <template #icon><n-icon size="16"><TrashOutline /></n-icon></template>
58
+ <template #icon
59
+ ><n-icon size="16"><TrashOutline /></n-icon
60
+ ></template>
41
61
  </n-button>
42
62
  </template>
43
63
  确定删除场景「{{ profile.name }}」?
@@ -82,7 +102,12 @@
82
102
  </n-spin>
83
103
 
84
104
  <!-- 自定义勾选弹窗 -->
85
- <n-modal v-model:show="showCustom" title="自定义技能组合" preset="card" style="width: 480px">
105
+ <n-modal
106
+ v-model:show="showCustom"
107
+ title="自定义技能组合"
108
+ preset="card"
109
+ style="width: 480px"
110
+ >
86
111
  <n-checkbox-group v-model:value="customSelected">
87
112
  <n-space vertical>
88
113
  <n-checkbox
@@ -94,7 +119,11 @@
94
119
  </n-space>
95
120
  </n-checkbox-group>
96
121
  <template #footer>
97
- <n-button type="primary" :loading="customLoading" @click="onApplyCustom">
122
+ <n-button
123
+ type="primary"
124
+ :loading="customLoading"
125
+ @click="onApplyCustom"
126
+ >
98
127
  确认安装
99
128
  </n-button>
100
129
  </template>
@@ -197,8 +226,11 @@ marked.use({
197
226
  return `<pre><button class="copy-btn" onclick="navigator.clipboard.writeText(this.parentNode.querySelector('code').textContent);this.textContent='已复制';setTimeout(()=>this.textContent='复制',1500)">复制</button><code class="hljs language-${language}">${highlighted}</code></pre>`;
198
227
  },
199
228
  link({ href, text }) {
200
- const isExternal = href && (href.startsWith("http://") || href.startsWith("https://"));
201
- const target = isExternal ? ' target="_blank" rel="noopener noreferrer"' : "";
229
+ const isExternal =
230
+ href && (href.startsWith("http://") || href.startsWith("https://"));
231
+ const target = isExternal
232
+ ? ' target="_blank" rel="noopener noreferrer"'
233
+ : "";
202
234
  return `<a href="${href}"${target}>${text}</a>`;
203
235
  },
204
236
  },
@@ -209,6 +241,7 @@ const message = useMessage();
209
241
 
210
242
  // 技能说明 README
211
243
  const skillsReadmeContent = ref(null);
244
+ const skillsReadmeOpen = ref(true);
212
245
  const renderedSkillsReadme = ref("");
213
246
 
214
247
  const profiles = ref([]);
@@ -257,8 +290,8 @@ async function loadSkillsReadme() {
257
290
  try {
258
291
  const res = await getSkillsReadme();
259
292
  if (res.content) {
260
- skillsReadmeContent.value = res.content;
261
293
  renderedSkillsReadme.value = renderMd(res.content);
294
+ skillsReadmeContent.value = res.content;
262
295
  }
263
296
  } catch {
264
297
  // 静默失败
@@ -301,7 +334,9 @@ function openEdit(profile) {
301
334
  }
302
335
 
303
336
  function openCustomDialog() {
304
- customSelected.value = allSkills.value.filter((s) => s.enabled).map((s) => s.name);
337
+ customSelected.value = allSkills.value
338
+ .filter((s) => s.enabled)
339
+ .map((s) => s.name);
305
340
  showCustom.value = true;
306
341
  }
307
342
 
@@ -402,10 +437,6 @@ onMounted(() => {
402
437
  font-weight: 600;
403
438
  }
404
439
 
405
- .readme-collapse {
406
- margin-bottom: 20px;
407
- }
408
-
409
440
  .scene-grid {
410
441
  display: grid;
411
442
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));