mdk-skills 2.2.21 → 2.2.23

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 (134) hide show
  1. package/.claude/.install.log +3 -0
  2. package/.claude/backups/20260511.145306/.install.log +39 -0
  3. package/.claude/backups/20260511.145306/profiles.json +22 -0
  4. package/.claude/backups/20260511.145306/settings.json +11 -0
  5. package/.claude/backups/CLAUDE.md.20260511.145306 +131 -0
  6. package/.claude/profiles.json +10 -61
  7. package/.claude/settings.json +9 -27
  8. package/package.json +9 -4
  9. package/scripts/core.js +49 -4
  10. package/scripts/web-ui/dist/assets/index-B3SLlTdd.css +1 -0
  11. package/scripts/web-ui/dist/assets/index-DanvMbHP.js +7440 -0
  12. package/scripts/web-ui/dist/index.html +13 -0
  13. package/scripts/web-ui/server.js +1013 -860
  14. package/scripts/web-ui/src/App.vue +148 -125
  15. package/scripts/web-ui/src/api/skills.js +20 -0
  16. package/scripts/web-ui/src/components/SkillCard.vue +9 -0
  17. package/scripts/web-ui/src/components/StatusBar.vue +13 -0
  18. package/scripts/web-ui/src/styles/main.css +105 -1
  19. package/scripts/web-ui/src/utils/usage.js +46 -0
  20. package/scripts/web-ui/src/views/Dashboard.vue +389 -20
  21. package/scripts/web-ui/src/views/SceneSwitch.vue +4 -0
  22. package/scripts/web-ui/src/views/Settings.vue +44 -2
  23. package/scripts/web-ui/vite.config.js +11 -0
  24. package/.claude/backups/20260510.153300/.install.log +0 -10
  25. package/.claude/backups/20260510.153300/profiles.json +0 -67
  26. package/.claude/backups/20260510.153300/settings.json +0 -29
  27. package/.claude/backups/20260510.153300/skills/frontend-code-review/.meta.json +0 -6
  28. package/.claude/backups/20260510.153300/skills/frontend-code-review/SKILL.md +0 -167
  29. package/.claude/backups/20260510.153300/skills/frontend-code-review/references/checklist.md +0 -298
  30. package/.claude/backups/20260510.153300/skills/frontend-design/.meta.json +0 -6
  31. package/.claude/backups/20260510.153300/skills/frontend-design/LICENSE.txt +0 -177
  32. package/.claude/backups/20260510.153300/skills/frontend-design/SKILL.md +0 -42
  33. package/.claude/backups/20260510.153300/skills/skill-creator/.meta.json +0 -6
  34. package/.claude/backups/20260510.153300/skills/skill-creator/SKILL.md +0 -356
  35. package/.claude/backups/20260510.153300/skills/skill-creator/references/output-patterns.md +0 -82
  36. package/.claude/backups/20260510.153300/skills/skill-creator/references/workflows.md +0 -28
  37. package/.claude/backups/20260510.153300/skills/skill-creator/scripts/init_skill.py +0 -303
  38. package/.claude/backups/20260510.153300/skills/skill-creator/scripts/package_skill.py +0 -110
  39. package/.claude/backups/20260510.153300/skills/skill-creator/scripts/quick_validate.py +0 -95
  40. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/.meta.json +0 -6
  41. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/SKILL.md +0 -228
  42. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/charts.csv +0 -26
  43. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/colors.csv +0 -97
  44. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/landing.csv +0 -31
  45. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/products.csv +0 -97
  46. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/prompts.csv +0 -24
  47. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  48. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  49. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  50. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  51. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  52. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  53. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
  54. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  55. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  56. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  57. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/styles.csv +0 -59
  58. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/typography.csv +0 -58
  59. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  60. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/scripts/core.py +0 -238
  61. package/.claude/backups/20260510.153300/skills/ui-ux-pro-max/scripts/search.py +0 -61
  62. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/.meta.json +0 -6
  63. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/SKILL.md +0 -26
  64. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -292
  65. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -174
  66. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/references/service-layer.md +0 -198
  67. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -1125
  68. package/.claude/backups/20260510.153300/skills/v3-fe-biz-patterns/references/use-loading.md +0 -114
  69. package/.claude/backups/20260510.153300/skills/vue/.meta.json +0 -6
  70. package/.claude/backups/20260510.153300/skills/vue/SKILL.md +0 -103
  71. package/.claude/backups/20260510.153300/skills/vue/references/components.md +0 -323
  72. package/.claude/backups/20260510.153300/skills/vue/references/composables.md +0 -358
  73. package/.claude/backups/20260510.153300/skills/vue/references/directives.md +0 -225
  74. package/.claude/backups/20260510.153300/skills/vue/references/gotchas.md +0 -438
  75. package/.claude/backups/20260510.153300/skills/vue/references/provide-inject.md +0 -174
  76. package/.claude/backups/20260510.153300/skills/vue/references/reactivity.md +0 -289
  77. package/.claude/backups/20260510.153300/skills/vue/references/router.md +0 -181
  78. package/.claude/backups/20260510.153300/skills/vue/references/testing.md +0 -294
  79. package/.claude/backups/20260510.153300/skills/vue/references/typescript.md +0 -172
  80. package/.claude/backups/20260510.153300/skills/vue/references/utils-client.md +0 -156
  81. package/.claude/skills/frontend-code-review/.meta.json +0 -6
  82. package/.claude/skills/frontend-code-review/SKILL.md +0 -167
  83. package/.claude/skills/frontend-code-review/references/checklist.md +0 -298
  84. package/.claude/skills/frontend-design/.meta.json +0 -6
  85. package/.claude/skills/frontend-design/LICENSE.txt +0 -177
  86. package/.claude/skills/frontend-design/SKILL.md +0 -42
  87. package/.claude/skills/skill-creator/.meta.json +0 -6
  88. package/.claude/skills/skill-creator/SKILL.md +0 -356
  89. package/.claude/skills/skill-creator/references/output-patterns.md +0 -82
  90. package/.claude/skills/skill-creator/references/workflows.md +0 -28
  91. package/.claude/skills/skill-creator/scripts/init_skill.py +0 -303
  92. package/.claude/skills/skill-creator/scripts/package_skill.py +0 -110
  93. package/.claude/skills/skill-creator/scripts/quick_validate.py +0 -95
  94. package/.claude/skills/ui-ux-pro-max/.meta.json +0 -6
  95. package/.claude/skills/ui-ux-pro-max/SKILL.md +0 -228
  96. package/.claude/skills/ui-ux-pro-max/data/charts.csv +0 -26
  97. package/.claude/skills/ui-ux-pro-max/data/colors.csv +0 -97
  98. package/.claude/skills/ui-ux-pro-max/data/landing.csv +0 -31
  99. package/.claude/skills/ui-ux-pro-max/data/products.csv +0 -97
  100. package/.claude/skills/ui-ux-pro-max/data/prompts.csv +0 -24
  101. package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  102. package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  103. package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  104. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  105. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  106. package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  107. package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
  108. package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  109. package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  110. package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  111. package/.claude/skills/ui-ux-pro-max/data/styles.csv +0 -59
  112. package/.claude/skills/ui-ux-pro-max/data/typography.csv +0 -58
  113. package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  114. package/.claude/skills/ui-ux-pro-max/scripts/core.py +0 -238
  115. package/.claude/skills/ui-ux-pro-max/scripts/search.py +0 -61
  116. package/.claude/skills/v3-fe-biz-patterns/.meta.json +0 -6
  117. package/.claude/skills/v3-fe-biz-patterns/SKILL.md +0 -26
  118. package/.claude/skills/v3-fe-biz-patterns/references/infinite-scroll.md +0 -292
  119. package/.claude/skills/v3-fe-biz-patterns/references/pinia-store.md +0 -174
  120. package/.claude/skills/v3-fe-biz-patterns/references/service-layer.md +0 -198
  121. package/.claude/skills/v3-fe-biz-patterns/references/tab-anchor.md +0 -1125
  122. package/.claude/skills/v3-fe-biz-patterns/references/use-loading.md +0 -114
  123. package/.claude/skills/vue/.meta.json +0 -6
  124. package/.claude/skills/vue/SKILL.md +0 -103
  125. package/.claude/skills/vue/references/components.md +0 -323
  126. package/.claude/skills/vue/references/composables.md +0 -358
  127. package/.claude/skills/vue/references/directives.md +0 -225
  128. package/.claude/skills/vue/references/gotchas.md +0 -438
  129. package/.claude/skills/vue/references/provide-inject.md +0 -174
  130. package/.claude/skills/vue/references/reactivity.md +0 -289
  131. package/.claude/skills/vue/references/router.md +0 -181
  132. package/.claude/skills/vue/references/testing.md +0 -294
  133. package/.claude/skills/vue/references/typescript.md +0 -172
  134. package/.claude/skills/vue/references/utils-client.md +0 -156
@@ -1,125 +1,148 @@
1
- <template>
2
- <n-message-provider>
3
- <n-notification-provider>
4
- <n-config-provider :theme="theme" :locale="zhCN" :date-locale="dateZhCN">
5
- <n-layout class="app-layout">
6
- <!-- 导航栏 -->
7
- <n-layout-header class="app-header" bordered>
8
- <div class="header-inner">
9
- <div class="header-left">
10
- <span class="logo">mdk-skills</span>
11
- <n-menu
12
- v-model:value="activeKey"
13
- mode="horizontal"
14
- :options="menuOptions"
15
- @update:value="onMenuChange"
16
- />
17
- </div>
18
- <n-tag
19
- v-if="statusData"
20
- :type="statusData.sourcePath ? 'success' : 'default'"
21
- size="small"
22
- >
23
- {{ statusData.sourcePath ? "本地源" : "npm 源" }}
24
- </n-tag>
25
- </div>
26
- </n-layout-header>
27
-
28
- <!-- 状态条 -->
29
- <StatusBar v-if="statusData" :data="statusData" />
30
-
31
- <!-- 内容区 -->
32
- <n-layout-content class="app-content">
33
- <transition name="fade" mode="out-in">
34
- <router-view @refresh="loadStatus" />
35
- </transition>
36
- </n-layout-content>
37
- </n-layout>
38
- </n-config-provider>
39
- </n-notification-provider>
40
- </n-message-provider>
41
- </template>
42
-
43
- <script setup>
44
- import { h, ref, onMounted, computed } from "vue";
45
- import { useRouter, useRoute } from "vue-router";
46
- import { NIcon, zhCN, dateZhCN } from "naive-ui";
47
- import {
48
- AppsOutline,
49
- SwapHorizontalOutline,
50
- CogOutline,
51
- DocumentTextOutline,
52
- } from "@vicons/ionicons5";
53
- import StatusBar from "./components/StatusBar.vue";
54
- import { getStatus } from "./api/skills";
55
-
56
- const router = useRouter();
57
- const route = useRoute();
58
-
59
- const statusData = ref(null);
60
-
61
- const theme = ref(null);
62
-
63
- const menuOptions = [
64
- {
65
- label: "仪表盘",
66
- key: "Dashboard",
67
- icon: () => h(NIcon, null, { default: () => h(AppsOutline) }),
68
- },
69
- {
70
- label: "场景切换",
71
- key: "Scenes",
72
- icon: () => h(NIcon, null, { default: () => h(SwapHorizontalOutline) }),
73
- },
74
- {
75
- label: "设置",
76
- key: "Settings",
77
- icon: () => h(NIcon, null, { default: () => h(CogOutline) }),
78
- },
79
- {
80
- label: "CLAUDE.md",
81
- key: "ClaudeMd",
82
- icon: () => h(NIcon, null, { default: () => h(DocumentTextOutline) }),
83
- },
84
- ];
85
-
86
- const activeKey = ref(route.name || "Dashboard");
87
-
88
- function onMenuChange(key) {
89
- router.push({ name: key });
90
- }
91
-
92
- router.afterEach((to) => {
93
- activeKey.value = to.name;
94
- });
95
-
96
- async function loadStatus() {
97
- try {
98
- statusData.value = await getStatus();
99
- } catch {
100
- // 静默失败
101
- }
102
- }
103
-
104
- onMounted(loadStatus);
105
- </script>
106
-
107
- <style>
108
- @import "./styles/main.css";
109
-
110
- .fade-enter-active,
111
- .fade-leave-active {
112
- transition:
113
- opacity 0.9s ease,
114
- transform 0.9s ease;
115
- }
116
-
117
- .fade-enter-from {
118
- opacity: 0;
119
- transform: translateY(6px);
120
- }
121
-
122
- .fade-leave-to {
123
- opacity: 0;
124
- }
125
- </style>
1
+ <template>
2
+ <n-message-provider>
3
+ <n-notification-provider>
4
+ <n-config-provider :theme="theme" :locale="zhCN" :date-locale="dateZhCN">
5
+ <n-layout class="app-layout">
6
+ <!-- 导航栏 -->
7
+ <n-layout-header class="app-header" bordered>
8
+ <div class="header-inner">
9
+ <div class="header-left">
10
+ <span class="logo">mdk-skills</span>
11
+ <n-menu
12
+ v-model:value="activeKey"
13
+ mode="horizontal"
14
+ :options="menuOptions"
15
+ @update:value="onMenuChange"
16
+ />
17
+ </div>
18
+ <div class="header-right">
19
+ <n-tag
20
+ v-if="statusData"
21
+ :type="statusData.sourcePath ? 'success' : 'default'"
22
+ size="small"
23
+ >
24
+ {{ statusData.sourcePath ? "本地源" : "npm 源" }}
25
+ </n-tag>
26
+ <n-button quaternary size="small" @click="toggleTheme">
27
+ <template #icon>
28
+ <n-icon><MoonOutline v-if="!darkMode" /><SunnyOutline v-else /></n-icon>
29
+ </template>
30
+ </n-button>
31
+ </div>
32
+ </div>
33
+ </n-layout-header>
34
+
35
+ <!-- 状态条 -->
36
+ <StatusBar v-if="statusData" :data="statusData" />
37
+
38
+ <!-- 内容区 -->
39
+ <n-layout-content class="app-content">
40
+ <transition name="fade" mode="out-in">
41
+ <router-view @refresh="loadStatus" />
42
+ </transition>
43
+ </n-layout-content>
44
+ </n-layout>
45
+ </n-config-provider>
46
+ </n-notification-provider>
47
+ </n-message-provider>
48
+ </template>
49
+
50
+ <script setup>
51
+ import { h, ref, onMounted, computed, watch } from "vue";
52
+ import { useRouter, useRoute } from "vue-router";
53
+ import { NIcon, zhCN, dateZhCN, darkTheme } from "naive-ui";
54
+ import {
55
+ AppsOutline,
56
+ SwapHorizontalOutline,
57
+ CogOutline,
58
+ DocumentTextOutline,
59
+ MoonOutline,
60
+ SunnyOutline,
61
+ } from "@vicons/ionicons5";
62
+ import StatusBar from "./components/StatusBar.vue";
63
+ import { getStatus } from "./api/skills";
64
+
65
+ const router = useRouter();
66
+ const route = useRoute();
67
+
68
+ const statusData = ref(null);
69
+
70
+ const darkMode = ref(localStorage.getItem("mdk-theme") === "dark");
71
+
72
+ const theme = computed(() => (darkMode.value ? darkTheme : null));
73
+
74
+ watch(darkMode, (val) => {
75
+ localStorage.setItem("mdk-theme", val ? "dark" : "light");
76
+ document.documentElement.setAttribute("data-theme", val ? "dark" : "light");
77
+ });
78
+
79
+ function toggleTheme() {
80
+ darkMode.value = !darkMode.value;
81
+ }
82
+
83
+ const menuOptions = [
84
+ {
85
+ label: "仪表盘",
86
+ key: "Dashboard",
87
+ icon: () => h(NIcon, null, { default: () => h(AppsOutline) }),
88
+ },
89
+ {
90
+ label: "场景切换",
91
+ key: "Scenes",
92
+ icon: () => h(NIcon, null, { default: () => h(SwapHorizontalOutline) }),
93
+ },
94
+ {
95
+ label: "设置",
96
+ key: "Settings",
97
+ icon: () => h(NIcon, null, { default: () => h(CogOutline) }),
98
+ },
99
+ {
100
+ label: "CLAUDE.md",
101
+ key: "ClaudeMd",
102
+ icon: () => h(NIcon, null, { default: () => h(DocumentTextOutline) }),
103
+ },
104
+ ];
105
+
106
+ const activeKey = ref(route.name || "Dashboard");
107
+
108
+ function onMenuChange(key) {
109
+ router.push({ name: key });
110
+ }
111
+
112
+ router.afterEach((to) => {
113
+ activeKey.value = to.name;
114
+ });
115
+
116
+ async function loadStatus() {
117
+ try {
118
+ statusData.value = await getStatus();
119
+ } catch {
120
+ // 静默失败
121
+ }
122
+ }
123
+
124
+ onMounted(() => {
125
+ loadStatus();
126
+ document.documentElement.setAttribute("data-theme", darkMode.value ? "dark" : "light");
127
+ });
128
+ </script>
129
+
130
+ <style>
131
+ @import "./styles/main.css";
132
+
133
+ .fade-enter-active,
134
+ .fade-leave-active {
135
+ transition:
136
+ opacity 0.9s ease,
137
+ transform 0.9s ease;
138
+ }
139
+
140
+ .fade-enter-from {
141
+ opacity: 0;
142
+ transform: translateY(6px);
143
+ }
144
+
145
+ .fade-leave-to {
146
+ opacity: 0;
147
+ }
148
+ </style>
@@ -102,6 +102,26 @@ export function getSkillReadme(name) {
102
102
  return request("/skills/" + encodeURIComponent(name) + "/readme");
103
103
  }
104
104
 
105
+ export function updateSkillMeta(name, data) {
106
+ return request("/skills/" + encodeURIComponent(name) + "/meta", {
107
+ method: "PATCH",
108
+ body: JSON.stringify(data),
109
+ });
110
+ }
111
+
112
+ export function pullSkills(url) {
113
+ return request("/skills/pull", {
114
+ method: "POST",
115
+ body: JSON.stringify({ url }),
116
+ });
117
+ }
118
+
119
+ export function deleteSkill(name) {
120
+ return request("/skills/" + encodeURIComponent(name), {
121
+ method: "DELETE",
122
+ });
123
+ }
124
+
105
125
  export function createReadme(data) {
106
126
  return request("/readme/create", {
107
127
  method: "POST",
@@ -14,6 +14,9 @@
14
14
  <n-tag v-for="tag in skill.tags" :key="tag" size="tiny" :bordered="false">
15
15
  {{ tag }}
16
16
  </n-tag>
17
+ <n-tag v-if="usages > 0" size="tiny" type="warning" :bordered="false">
18
+ 使用 {{ usages }} 次
19
+ </n-tag>
17
20
  </div>
18
21
  <p class="skill-desc">{{ skill.description || "暂无描述" }}</p>
19
22
  </n-card>
@@ -23,9 +26,11 @@
23
26
  import { ref } from "vue";
24
27
  import { useMessage } from "naive-ui";
25
28
  import { toggleSkill } from "../api/skills";
29
+ import { recordUsage } from "../utils/usage";
26
30
 
27
31
  const props = defineProps({
28
32
  skill: { type: Object, required: true },
33
+ usages: { type: Number, default: 0 },
29
34
  });
30
35
 
31
36
  const emit = defineEmits(["refresh", "click"]);
@@ -37,6 +42,7 @@ async function onToggle(value) {
37
42
  try {
38
43
  const res = await toggleSkill(props.skill.name, value);
39
44
  if (res.ok) {
45
+ if (value) recordUsage(props.skill.name);
40
46
  message.success(`技能 "${props.skill.name}" 已${value ? "启用" : "停用"}`);
41
47
  emit("refresh");
42
48
  }
@@ -76,5 +82,8 @@ async function onToggle(value) {
76
82
  font-size: 13px;
77
83
  color: #666;
78
84
  margin: 0;
85
+ overflow: hidden;
86
+ text-overflow: ellipsis;
87
+ white-space: nowrap;
79
88
  }
80
89
  </style>
@@ -72,3 +72,16 @@ defineProps({
72
72
  background: #e0e0e0;
73
73
  }
74
74
  </style>
75
+
76
+ <style>
77
+ [data-theme="dark"] .status-bar {
78
+ background: #1a1a2e;
79
+ border-bottom-color: #333;
80
+ }
81
+ [data-theme="dark"] .status-item {
82
+ color: #aaa;
83
+ }
84
+ [data-theme="dark"] .status-divider {
85
+ background: #333;
86
+ }
87
+ </style>
@@ -10,7 +10,16 @@ html, body, #app {
10
10
  }
11
11
 
12
12
  body {
13
- overflow-y: scroll;
13
+ overflow-y: auto;
14
+ }
15
+
16
+ /* 全局隐藏所有滚动条,能滚但不显示 */
17
+ * {
18
+ scrollbar-width: none;
19
+ -ms-overflow-style: none;
20
+ }
21
+ *::-webkit-scrollbar {
22
+ display: none;
14
23
  }
15
24
 
16
25
  .app-layout {
@@ -190,3 +199,98 @@ body {
190
199
  color: #2080f0;
191
200
  border-color: #2080f0;
192
201
  }
202
+
203
+ /* ---------- 导航栏右侧 ---------- */
204
+ .header-right {
205
+ display: flex;
206
+ align-items: center;
207
+ gap: 8px;
208
+ }
209
+
210
+ /* ---------- 暗黑主题 ---------- */
211
+ [data-theme="dark"] html,
212
+ [data-theme="dark"] body,
213
+ [data-theme="dark"] #app {
214
+ background: #1a1a2e;
215
+ }
216
+
217
+ [data-theme="dark"] .app-header {
218
+ background: #1a1a2e;
219
+ border-bottom-color: #333;
220
+ }
221
+
222
+ [data-theme="dark"] .app-content {
223
+ background: transparent;
224
+ }
225
+
226
+ [data-theme="dark"] .readme-fold {
227
+ border-color: #333;
228
+ }
229
+ [data-theme="dark"] .fold-header {
230
+ background: #252538;
231
+ color: #e0e0e0;
232
+ }
233
+ [data-theme="dark"] .fold-header:hover {
234
+ background: #2a2a40;
235
+ }
236
+ [data-theme="dark"] .fold-body {
237
+ background: #1e1e32;
238
+ }
239
+ [data-theme="dark"] .fold-arrow {
240
+ color: #888;
241
+ }
242
+
243
+ [data-theme="dark"] .markdown-content {
244
+ color: #ccc;
245
+ }
246
+ [data-theme="dark"] .markdown-content h1,
247
+ [data-theme="dark"] .markdown-content h2 {
248
+ border-bottom-color: #333;
249
+ color: #eee;
250
+ }
251
+ [data-theme="dark"] .markdown-content h3,
252
+ [data-theme="dark"] .markdown-content h4 {
253
+ color: #eee;
254
+ }
255
+ [data-theme="dark"] .markdown-content code {
256
+ background: #2a2a40;
257
+ color: #e06c9f;
258
+ }
259
+ [data-theme="dark"] .markdown-content pre {
260
+ border-color: #333;
261
+ }
262
+ [data-theme="dark"] .markdown-content pre code {
263
+ background: #1e1e2e;
264
+ color: #d4d4d4;
265
+ }
266
+ [data-theme="dark"] .markdown-content blockquote {
267
+ background: #252538;
268
+ border-left-color: #4a6cf7;
269
+ color: #bbb;
270
+ }
271
+ [data-theme="dark"] .markdown-content a {
272
+ color: #6a8cff;
273
+ }
274
+ [data-theme="dark"] .markdown-content th {
275
+ background: #252538;
276
+ }
277
+ [data-theme="dark"] .markdown-content td {
278
+ border-color: #333;
279
+ }
280
+ [data-theme="dark"] .markdown-content tr:nth-child(even) td {
281
+ background: #222238;
282
+ }
283
+ [data-theme="dark"] .markdown-content hr {
284
+ border-top-color: #333;
285
+ }
286
+ [data-theme="dark"] .markdown-content img {
287
+ filter: brightness(0.85);
288
+ }
289
+
290
+ [data-theme="dark"] .page-header h2 {
291
+ color: #e0e0e0;
292
+ }
293
+
294
+ [data-theme="dark"] .scene-desc {
295
+ color: #aaa;
296
+ }
@@ -0,0 +1,46 @@
1
+ const STORAGE_KEY = "mdk-usage";
2
+
3
+ function getRaw() {
4
+ try {
5
+ return JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}");
6
+ } catch {
7
+ return {};
8
+ }
9
+ }
10
+
11
+ function saveRaw(data) {
12
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
13
+ }
14
+
15
+ /** 记录某个技能被使用一次 */
16
+ export function recordUsage(name) {
17
+ const data = getRaw();
18
+ const entry = data[name] || { count: 0 };
19
+ entry.count += 1;
20
+ entry.lastUsed = Date.now();
21
+ data[name] = entry;
22
+ saveRaw(data);
23
+ }
24
+
25
+ /** 获取完整使用统计数据 */
26
+ export function getUsageMap() {
27
+ return getRaw();
28
+ }
29
+
30
+ /**
31
+ * 对技能列表排序
32
+ * @param {Array} skills - 技能数组
33
+ * @param {'name'|'frequency'|'recent'} by - 排序方式
34
+ */
35
+ export function sortSkills(skills, by) {
36
+ const usage = getRaw();
37
+ const list = [...skills];
38
+ if (by === "frequency") {
39
+ list.sort((a, b) => (usage[b.name]?.count || 0) - (usage[a.name]?.count || 0));
40
+ } else if (by === "recent") {
41
+ list.sort((a, b) => (usage[b.name]?.lastUsed || 0) - (usage[a.name]?.lastUsed || 0));
42
+ } else {
43
+ list.sort((a, b) => a.name.localeCompare(b.name));
44
+ }
45
+ return list;
46
+ }