Skip to content

Commit b7ac273

Browse files
committed
feat(skill): 添加 IDE 选择和输出目录配置功能
- 新增 IDE 选项配置,支持 Cursor、Claude、Qoder、Codex、Kiro、Lingma 等编辑器 - 添加默认输出目录映射逻辑,为不同 IDE 设置对应的技能文件存放路径 - 实现 IDE 选择界面,用户可点击切换不同的 IDE 选项 - 添加输出目录输入框,允许用户自定义技能下载路径 - 修改 NPX 命令,集成输出目录参数到 CLI 下载命令中 - 优化界面布局,调整组件间距和样式以适应新功能
1 parent c63d038 commit b7ac273

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed
3.84 KB
Loading

himarket-web/himarket-frontend/src/pages/SkillDetail.tsx

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,29 @@ import RelatedSkills from "../components/skill/RelatedSkills";
1919
import { copyToClipboard } from "../lib/utils";
2020
import { DetailSkeleton } from "../components/loading";
2121

22+
type IdeType = 'cursor' | 'kiro' | 'qoder' | 'lingma' | 'claude' | 'codex';
23+
24+
const IDE_OPTIONS: { value: IdeType; label: string; icon: string }[] = [
25+
{ value: 'cursor', label: 'Cursor', icon: 'https://aimg.alistatic.com/i/dm885X/UgW1Qzx0RPwrNIVs4sWlr-7b5511235d.svg' },
26+
{ value: 'claude', label: 'Claude', icon: 'https://img.alicdn.com/imgextra/i3/O1CN01JqyNKC1VmMU2MHdF9_!!6000000002695-55-tps-100-101.svg' },
27+
{ value: 'qoder', label: 'Qoder', icon: 'https://g.alicdn.com/qbase/qoder/0.0.65/favIcon.svg' },
28+
{ value: 'codex', label: 'Codex', icon: 'https://img.alicdn.com/imgextra/i3/O1CN011DvgjK1s54F8K000Q_!!6000000005714-0-tps-248-248.jpg' },
29+
{ value: 'kiro', label: 'Kiro', icon: '/kiro.png' },
30+
{ value: 'lingma', label: 'Lingma', icon: 'https://img.alicdn.com/imgextra/i2/O1CN01OR7j0c1OvKuJfKBAw_!!6000000001767-2-tps-280-280.png' },
31+
];
32+
33+
const getDefaultOutputDir = (ide: IdeType): string => {
34+
const dirMap: Record<IdeType, string> = {
35+
cursor: './.cursor/skills',
36+
kiro: './.kiro/skills',
37+
qoder: './.qoder/skills',
38+
lingma: './.lingma/skills',
39+
claude: './.claude/skills',
40+
codex: './.codex/skills',
41+
};
42+
return dirMap[ide];
43+
};
44+
2245
function inferLanguage(path: string): string {
2346
const fileName = path.split("/").pop()?.toLowerCase() ?? "";
2447
if (fileName === "dockerfile") return "dockerfile";
@@ -85,6 +108,8 @@ function SkillDetail() {
85108
const [versions, setVersions] = useState<SkillVersion[]>([]);
86109
const [selectedVersion, setSelectedVersion] = useState<string | undefined>();
87110
const [cliInfo, setCliInfo] = useState<SkillCliInfo | null>(null);
111+
const [selectedIde, setSelectedIde] = useState<IdeType>('qoder');
112+
const [outputDir, setOutputDir] = useState<string>('./.qoder/skills');
88113

89114
const handleDragStart = (e: React.MouseEvent) => {
90115
e.preventDefault();
@@ -554,14 +579,14 @@ function SkillDetail() {
554579
{/* Nacos CLI command */}
555580
{cliInfo && (
556581
<div className="px-4 py-3">
557-
<div className="flex items-center justify-between mb-2">
582+
<div className="flex items-center justify-between mb-3">
558583
<div className="flex items-center gap-1.5">
559584
<CodeOutlined className="text-gray-400 text-xs" />
560585
<span className="text-xs font-medium text-gray-500">NPX 下载</span>
561586
</div>
562587
<button
563588
onClick={() => {
564-
const cmd = `npx @nacos-group/cli --host ${cliInfo.nacosHost} skill-get ${cliInfo.resourceName}`;
589+
const cmd = `npx @nacos-group/cli --host ${cliInfo.nacosHost} skill-get ${cliInfo.resourceName} -o ${outputDir}`;
565590
copyToClipboard(cmd).then(() => {
566591
setCopied(true);
567592
setTimeout(() => setCopied(false), 2000);
@@ -572,9 +597,52 @@ function SkillDetail() {
572597
{copied ? <CheckOutlined className="text-green-500" /> : <CopyOutlined />}
573598
</button>
574599
</div>
600+
601+
{/* IDE Selection */}
602+
<div className="mb-3">
603+
<div className="text-xs text-gray-500 mb-2">选择 IDE</div>
604+
<div className="flex flex-wrap gap-2">
605+
{IDE_OPTIONS.map((ide) => (
606+
<button
607+
key={ide.value}
608+
onClick={() => {
609+
setSelectedIde(ide.value);
610+
setOutputDir(getDefaultOutputDir(ide.value));
611+
}}
612+
className={`flex items-center gap-1.5 px-2.5 py-1.5 rounded-md border text-xs transition-all ${
613+
selectedIde === ide.value
614+
? 'border-blue-500 bg-blue-50 text-blue-700'
615+
: 'border-gray-200 hover:border-gray-300 text-gray-600'
616+
}`}
617+
>
618+
{ide.icon && (
619+
<img
620+
src={ide.icon}
621+
alt={ide.label}
622+
className="w-4 h-4 object-contain"
623+
/>
624+
)}
625+
<span>{ide.label}</span>
626+
</button>
627+
))}
628+
</div>
629+
</div>
630+
631+
{/* Output Directory */}
632+
<div className="mb-3">
633+
<div className="text-xs text-gray-500 mb-1.5">输出目录</div>
634+
<input
635+
type="text"
636+
value={outputDir}
637+
onChange={(e) => setOutputDir(e.target.value)}
638+
className="w-full px-3 py-2 text-xs border border-gray-200 rounded-md focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 bg-white text-gray-700"
639+
placeholder="输入输出目录路径"
640+
/>
641+
</div>
642+
575643
<div className="rounded-md bg-gray-100 border border-gray-200 px-3 py-2">
576644
<code className="text-[12px] text-gray-700 break-all" style={{ fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace" }}>
577-
{`npx @nacos-group/cli --host ${cliInfo.nacosHost} skill-get ${cliInfo.resourceName}`}
645+
{`npx @nacos-group/cli --host ${cliInfo.nacosHost} skill-get ${cliInfo.resourceName} -o ${outputDir}`}
578646
</code>
579647
</div>
580648
</div>

0 commit comments

Comments
 (0)