Skip to content

Commit f2b94b0

Browse files
committed
feat: add search tinyvue icon mcp
1 parent 9b3770b commit f2b94b0

16 files changed

Lines changed: 19769 additions & 5 deletions

File tree

designer-demo/package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
"dev": "cross-env vite",
88
"build:alpha": "cross-env NODE_OPTIONS=--max-old-space-size=10240 vite build --mode alpha",
99
"build": "cross-env NODE_OPTIONS=--max-old-space-size=10240 vite build",
10+
"build:index": "tsx scripts/buildIndex.ts",
1011
"test": "vitest run",
1112
"test:watch": "vitest"
1213
},
1314
"dependencies": {
15+
"@modelcontextprotocol/sdk": "^1.0.4",
1416
"@opentiny/tiny-engine": "workspace:^",
1517
"@opentiny/tiny-engine-meta-register": "workspace:^",
1618
"@opentiny/tiny-engine-utils": "workspace:*",
@@ -21,13 +23,21 @@
2123
"@opentiny/vue-renderless": "~3.20.0",
2224
"@opentiny/vue-theme": "~3.20.0",
2325
"@vueuse/core": "^9.6.0",
24-
"vue": "^3.4.21"
26+
"fuse.js": "^7.0.0",
27+
"nodejieba": "^3.5.2",
28+
"pinyin": "^3.0.0",
29+
"pinyin-match": "^1.2.0",
30+
"vue": "^3.4.21",
31+
"zod": "^3.25.76"
2532
},
2633
"devDependencies": {
2734
"@opentiny/tiny-engine-mock": "workspace:^",
2835
"@opentiny/tiny-engine-vite-config": "workspace:^",
36+
"@types/node": "^20.0.0",
2937
"@vitejs/plugin-vue": "^5.1.2",
3038
"cross-env": "^7.0.3",
39+
"tsx": "^4.0.0",
40+
"typescript": "^5.8.3",
3141
"vite": "^5.4.2",
3242
"vitest": "3.0.9"
3343
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { IconIndexer } from '../src/mcp/services/iconIndexer.js';
2+
import { IconIndexData } from '../src/mcp/types/icon.js';
3+
import fs from 'fs';
4+
import path from 'path';
5+
import { fileURLToPath } from 'url';
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
10+
/**
11+
* 从 OpenTiny Vue Icon 库中提取所有图标名称
12+
*/
13+
function extractIconNames(): string[] {
14+
const iconLibPath = path.resolve('node_modules/@opentiny/vue-icon/lib');
15+
16+
if (!fs.existsSync(iconLibPath)) {
17+
console.error(`Error: Icon library not found at ${iconLibPath}`);
18+
console.error('Please ensure @opentiny/vue-icon is installed.');
19+
process.exit(1);
20+
}
21+
22+
const files = fs.readdirSync(iconLibPath);
23+
// 过滤出 .js 文件并去掉扩展名
24+
const iconNames = files
25+
.filter(f => f.endsWith('.js'))
26+
.map(f => f.replace(/\.js$/, ''));
27+
28+
return iconNames;
29+
}
30+
31+
/**
32+
* 主函数:构建图标索引
33+
*/
34+
async function main() {
35+
console.log('🔍 Building icon index for OpenTiny Vue Icons...\n');
36+
37+
// 1. 提取图标名称
38+
console.log('📦 Extracting icon names from library...');
39+
const iconNames = extractIconNames();
40+
console.log(` Found ${iconNames.length} icons\n`);
41+
42+
// 2. 构建索引
43+
console.log('🔨 Building icon index...');
44+
const indexer = new IconIndexer();
45+
let iconIndex = indexer.buildIndex(iconNames);
46+
47+
// 3. 填充变体信息
48+
console.log('🔗 Filling variant information...');
49+
iconIndex = indexer.fillVariants(iconIndex);
50+
51+
// 4. 构建最终数据
52+
const indexData: IconIndexData = {
53+
version: '1.0.0',
54+
lastUpdated: new Date().toISOString(),
55+
total: iconIndex.length,
56+
icons: iconIndex,
57+
};
58+
59+
// 5. 写入文件
60+
const outputPath = path.resolve(__dirname, '../src/mcp/data/iconIndex.json');
61+
fs.writeFileSync(outputPath, JSON.stringify(indexData, null, 2), 'utf-8');
62+
63+
console.log('\n✅ Index built successfully!');
64+
console.log(`📊 Total icons: ${iconIndex.length}`);
65+
console.log(`📁 Output: ${outputPath}`);
66+
67+
// 6. 显示统计信息
68+
const categoryStats = new Map<string, number>();
69+
for (const icon of iconIndex) {
70+
categoryStats.set(icon.category, (categoryStats.get(icon.category) || 0) + 1);
71+
}
72+
73+
console.log('\n📈 Category distribution:');
74+
for (const [category, count] of Array.from(categoryStats.entries()).sort((a, b) => b[1] - a[1])) {
75+
console.log(` ${category}: ${count}`);
76+
}
77+
78+
// 7. 显示一些示例
79+
console.log('\n📝 Sample icons:');
80+
iconIndex.slice(0, 5).forEach(icon => {
81+
console.log(` - ${icon.name} (${icon.componentName})`);
82+
console.log(` Keywords: ${icon.keywords.en.slice(0, 3).join(', ')}`);
83+
console.log(` 中文: ${icon.keywords.zh.slice(0, 2).join(', ') || '无'}`);
84+
console.log(` 拼音: ${icon.keywords.pinyin.slice(0, 2).join(', ') || '无'}`);
85+
console.log(` 首字母: ${icon.keywords.pinyinAbbr.join(', ') || '无'}`);
86+
});
87+
}
88+
89+
main().catch(error => {
90+
console.error('❌ Error building index:', error);
91+
process.exit(1);
92+
});

designer-demo/src/main.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@
1111
*/
1212
import { configurators } from './configurators/'
1313
import 'virtual:svg-icons-register'
14+
import mcp from './mcp'
1415

1516
async function startApp() {
1617
const registry = await import('../registry')
17-
const { init } = await import('@opentiny/tiny-engine')
18+
const { init, getMetaApi, META_SERVICE } = await import('@opentiny/tiny-engine')
1819

19-
init({
20+
await init({
2021
// 合并多个注册表
2122
registry: [registry.default],
2223
configurators,
2324
createAppSignal: ['global_service_init_finish']
2425
})
26+
getMetaApi(META_SERVICE.McpService).registerTools(mcp.tools)
2527
}
2628

2729
startApp()

0 commit comments

Comments
 (0)