feat(skills): add skill deletion and improve UI/UX

- Add skill deletion functionality with confirmation dialog
- Protect builtin skills from deletion
- Optimize skill card layout (badge and enable button near menu)
- Change enable button to icon-only with theme color
- Improve card selection and hover states
- Fix skill hub installation state tracking (per-skill)
- Add proper i18n for delete feature (en/zh)
- Add loading states to delete confirmation dialog
- Remove manual refetch calls (use query invalidation)
This commit is contained in:
catlog22
2026-02-24 21:06:34 +08:00
parent 6c9ad9a9f3
commit 33e12a31ac
6 changed files with 219 additions and 24 deletions

View File

@@ -1265,6 +1265,25 @@ export async function fetchSkillDetail(
return fetchApi<{ skill: Skill }>(url);
}
/**
* Delete a skill
* @param skillName - Name of the skill to delete
* @param location - Location of the skill (project or user)
* @param projectPath - Optional project path
* @param cliType - CLI type (claude or codex)
*/
export async function deleteSkill(
skillName: string,
location: 'project' | 'user',
projectPath?: string,
cliType: 'claude' | 'codex' = 'claude'
): Promise<{ success: boolean }> {
return fetchApi<{ success: boolean }>(`/api/skills/${encodeURIComponent(skillName)}`, {
method: 'DELETE',
body: JSON.stringify({ location, projectPath, cliType }),
});
}
/**
* Validate a skill folder for import
*/
@@ -1298,6 +1317,42 @@ export async function createSkill(params: {
});
}
/**
* Read a skill file content
*/
export async function readSkillFile(params: {
skillName: string;
fileName: string;
location: 'project' | 'user';
projectPath?: string;
cliType?: 'claude' | 'codex';
}): Promise<{ content: string; fileName: string; path: string }> {
const { skillName, fileName, location, projectPath, cliType = 'claude' } = params;
const encodedSkillName = encodeURIComponent(skillName);
const url = `/api/skills/${encodedSkillName}/file?filename=${encodeURIComponent(fileName)}&location=${location}&cliType=${cliType}${projectPath ? `&path=${encodeURIComponent(projectPath)}` : ''}`;
return fetchApi(url);
}
/**
* Write a skill file content
*/
export async function writeSkillFile(params: {
skillName: string;
fileName: string;
content: string;
location: 'project' | 'user';
projectPath?: string;
cliType?: 'claude' | 'codex';
}): Promise<{ success: boolean; fileName: string; path: string }> {
const { skillName, fileName, content, location, projectPath, cliType = 'claude' } = params;
const encodedSkillName = encodeURIComponent(skillName);
const url = `/api/skills/${encodedSkillName}/file`;
return fetchApi(url, {
method: 'POST',
body: JSON.stringify({ content, fileName, location, projectPath, cliType }),
});
}
// ========== Commands API ==========
export interface Command {