mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-29 09:37:37 +08:00
feat(templates): add Claude Code Templates marketplace
- Add template repository management and component discovery - Implement template installation for agents, commands, hooks, MCPs, skills, settings - Support multi-app installation (Claude/Codex/Gemini) - Add frontend components for browsing and installing templates - Include i18n translations for zh/en/ja
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type {
|
||||
TemplateRepo,
|
||||
TemplateComponent,
|
||||
ComponentDetail,
|
||||
PaginatedResult,
|
||||
ComponentFilter,
|
||||
BatchInstallResult,
|
||||
InstalledComponent,
|
||||
ComponentType,
|
||||
} from "@/types/template";
|
||||
import type { AppType } from "./config";
|
||||
|
||||
export const templateApi = {
|
||||
// 模板仓库管理
|
||||
async listTemplateRepos(): Promise<TemplateRepo[]> {
|
||||
return invoke("list_template_repos");
|
||||
},
|
||||
|
||||
async addTemplateRepo(
|
||||
owner: string,
|
||||
name: string,
|
||||
branch: string,
|
||||
): Promise<void> {
|
||||
return invoke("add_template_repo", { owner, name, branch });
|
||||
},
|
||||
|
||||
async removeTemplateRepo(id: number): Promise<void> {
|
||||
return invoke("remove_template_repo", { id });
|
||||
},
|
||||
|
||||
async toggleTemplateRepo(id: number, enabled: boolean): Promise<void> {
|
||||
return invoke("toggle_template_repo", { id, enabled });
|
||||
},
|
||||
|
||||
// 模板索引刷新
|
||||
async refreshTemplateIndex(): Promise<void> {
|
||||
return invoke("refresh_template_index");
|
||||
},
|
||||
|
||||
// 模板组件查询
|
||||
async listTemplateComponents(
|
||||
filter: ComponentFilter,
|
||||
): Promise<PaginatedResult<TemplateComponent>> {
|
||||
return invoke("list_template_components", {
|
||||
componentType: filter.componentType,
|
||||
category: filter.category,
|
||||
search: filter.search,
|
||||
page: filter.page ?? 1,
|
||||
pageSize: filter.pageSize ?? 20,
|
||||
appType: filter.appType,
|
||||
});
|
||||
},
|
||||
|
||||
async getTemplateComponent(id: number): Promise<ComponentDetail> {
|
||||
return invoke("get_template_component", { id });
|
||||
},
|
||||
|
||||
async getComponentCategories(
|
||||
componentType?: ComponentType,
|
||||
): Promise<string[]> {
|
||||
return invoke("list_template_categories", { componentType });
|
||||
},
|
||||
|
||||
// 组件安装管理
|
||||
async installTemplateComponent(id: number, appType: AppType): Promise<void> {
|
||||
return invoke("install_template_component", { id, appType });
|
||||
},
|
||||
|
||||
async uninstallTemplateComponent(
|
||||
id: number,
|
||||
appType: AppType,
|
||||
): Promise<void> {
|
||||
return invoke("uninstall_template_component", { id, appType });
|
||||
},
|
||||
|
||||
async batchInstallComponents(
|
||||
ids: number[],
|
||||
appType: AppType,
|
||||
): Promise<BatchInstallResult> {
|
||||
return invoke("batch_install_template_components", { ids, appType });
|
||||
},
|
||||
|
||||
async listInstalledComponents(
|
||||
appType?: AppType,
|
||||
componentType?: ComponentType,
|
||||
): Promise<InstalledComponent[]> {
|
||||
return invoke("list_installed_components", { appType, componentType });
|
||||
},
|
||||
|
||||
// 组件内容预览
|
||||
async previewComponentContent(id: number): Promise<string> {
|
||||
return invoke("preview_component_content", { id });
|
||||
},
|
||||
|
||||
// 市场组合
|
||||
async listMarketplaceBundles(): Promise<
|
||||
import("@/types/template").MarketplaceBundle[]
|
||||
> {
|
||||
return invoke("list_marketplace_bundles");
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { templateApi } from "@/lib/api/template";
|
||||
import type { ComponentFilter, ComponentType } from "@/types/template";
|
||||
import type { AppType } from "@/lib/api/config";
|
||||
|
||||
// Query keys
|
||||
export const templateKeys = {
|
||||
all: ["templates"] as const,
|
||||
repos: () => [...templateKeys.all, "repos"] as const,
|
||||
components: (filter: ComponentFilter) =>
|
||||
[...templateKeys.all, "components", filter] as const,
|
||||
component: (id: number) => [...templateKeys.all, "component", id] as const,
|
||||
categories: (type?: ComponentType) =>
|
||||
[...templateKeys.all, "categories", type] as const,
|
||||
installed: (appType?: AppType, componentType?: ComponentType) =>
|
||||
[...templateKeys.all, "installed", appType, componentType] as const,
|
||||
preview: (id: number) => [...templateKeys.all, "preview", id] as const,
|
||||
bundles: () => [...templateKeys.all, "bundles"] as const,
|
||||
};
|
||||
|
||||
// Hooks - 模板仓库
|
||||
export function useTemplateRepos() {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.repos(),
|
||||
queryFn: templateApi.listTemplateRepos,
|
||||
});
|
||||
}
|
||||
|
||||
export function useAddTemplateRepo() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (params: { owner: string; name: string; branch: string }) =>
|
||||
templateApi.addTemplateRepo(params.owner, params.name, params.branch),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: templateKeys.repos() });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useRemoveTemplateRepo() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => templateApi.removeTemplateRepo(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: templateKeys.repos() });
|
||||
queryClient.invalidateQueries({ queryKey: templateKeys.components({}) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useToggleTemplateRepo() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (params: { id: number; enabled: boolean }) =>
|
||||
templateApi.toggleTemplateRepo(params.id, params.enabled),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: templateKeys.repos() });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Hooks - 模板索引
|
||||
export function useRefreshTemplateIndex() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: templateApi.refreshTemplateIndex,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: templateKeys.all });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Hooks - 模板组件查询
|
||||
export function useTemplateComponents(filter: ComponentFilter) {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.components(filter),
|
||||
queryFn: () => templateApi.listTemplateComponents(filter),
|
||||
});
|
||||
}
|
||||
|
||||
export function useTemplateComponent(id: number) {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.component(id),
|
||||
queryFn: () => templateApi.getTemplateComponent(id),
|
||||
enabled: id > 0,
|
||||
});
|
||||
}
|
||||
|
||||
export function useComponentCategories(componentType?: ComponentType) {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.categories(componentType),
|
||||
queryFn: () => templateApi.getComponentCategories(componentType),
|
||||
});
|
||||
}
|
||||
|
||||
// Hooks - 组件安装
|
||||
export function useInstallTemplateComponent() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (params: { id: number; appType: AppType }) =>
|
||||
templateApi.installTemplateComponent(params.id, params.appType),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: templateKeys.components({}),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: templateKeys.installed(),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUninstallTemplateComponent() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (params: { id: number; appType: AppType }) =>
|
||||
templateApi.uninstallTemplateComponent(params.id, params.appType),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: templateKeys.components({}),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: templateKeys.installed(),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useBatchInstallComponents() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (params: { ids: number[]; appType: AppType }) =>
|
||||
templateApi.batchInstallComponents(params.ids, params.appType),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: templateKeys.components({}),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: templateKeys.installed(),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useInstalledComponents(
|
||||
appType?: AppType,
|
||||
componentType?: ComponentType,
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.installed(appType, componentType),
|
||||
queryFn: () => templateApi.listInstalledComponents(appType, componentType),
|
||||
});
|
||||
}
|
||||
|
||||
// Hooks - 组件预览
|
||||
export function useComponentPreview(id: number) {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.preview(id),
|
||||
queryFn: () => templateApi.previewComponentContent(id),
|
||||
enabled: id > 0,
|
||||
});
|
||||
}
|
||||
|
||||
// Hooks - 市场组合
|
||||
export function useMarketplaceBundles() {
|
||||
return useQuery({
|
||||
queryKey: templateKeys.bundles(),
|
||||
queryFn: templateApi.listMarketplaceBundles,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user