Compare commits

...

3 Commits

Author SHA1 Message Date
YoVinchen 4454355aad fix(skill): use full key for deduplication to allow same-name skills from different repos 2025-11-26 09:26:23 +08:00
Jason 15c6e3aec8 refactor(ui): improve header toolbar layout and transitions
- Reorder toolbar buttons to keep Prompts and MCP icons aligned right
  (consistent position between Claude and Codex apps)
- Add smooth fade-in/out transition for Skills button with opacity,
  width, scale, and padding animations
- Hide Agents button temporarily (feature in development)
- Remove two divider lines for cleaner appearance
2025-11-25 23:36:48 +08:00
YoVinchen 6783a8a183 fix(provider): include icon fields when duplicating provider (#297) 2025-11-25 23:18:54 +08:00
2 changed files with 39 additions and 32 deletions
+4 -2
View File
@@ -353,11 +353,13 @@ impl SkillService {
} }
/// 去重技能列表 /// 去重技能列表
/// 使用完整的 key (owner/name:directory) 来区分不同仓库的同名技能
fn deduplicate_skills(skills: &mut Vec<Skill>) { fn deduplicate_skills(skills: &mut Vec<Skill>) {
let mut seen = HashMap::new(); let mut seen = HashMap::new();
skills.retain(|skill| { skills.retain(|skill| {
let key = skill.directory.to_lowercase(); // 使用完整 key 而非仅 directory,允许不同仓库的同名技能共存
if let std::collections::hash_map::Entry::Vacant(e) = seen.entry(key) { let unique_key = skill.key.to_lowercase();
if let std::collections::hash_map::Entry::Vacant(e) = seen.entry(unique_key) {
e.insert(true); e.insert(true);
true true
} else { } else {
+35 -30
View File
@@ -6,7 +6,7 @@ import {
Plus, Plus,
Settings, Settings,
ArrowLeft, ArrowLeft,
Bot, // Bot, // TODO: Agents 功能开发中,暂时不需要
Book, Book,
Wrench, Wrench,
Server, Server,
@@ -24,6 +24,7 @@ import {
import { checkAllEnvConflicts, checkEnvConflicts } from "@/lib/api/env"; import { checkAllEnvConflicts, checkEnvConflicts } from "@/lib/api/env";
import { useProviderActions } from "@/hooks/useProviderActions"; import { useProviderActions } from "@/hooks/useProviderActions";
import { extractErrorMessage } from "@/utils/errorUtils"; import { extractErrorMessage } from "@/utils/errorUtils";
import { cn } from "@/lib/utils";
import { AppSwitcher } from "@/components/AppSwitcher"; import { AppSwitcher } from "@/components/AppSwitcher";
import { ProviderList } from "@/components/providers/ProviderList"; import { ProviderList } from "@/components/providers/ProviderList";
import { AddProviderDialog } from "@/components/providers/AddProviderDialog"; import { AddProviderDialog } from "@/components/providers/AddProviderDialog";
@@ -217,6 +218,8 @@ function App() {
meta: provider.meta meta: provider.meta
? JSON.parse(JSON.stringify(provider.meta)) ? JSON.parse(JSON.stringify(provider.meta))
: undefined, // 深拷贝 : undefined, // 深拷贝
icon: provider.icon,
iconColor: provider.iconColor,
}; };
// 2️⃣ 如果原供应商有 sortIndex,需要将后续所有供应商的 sortIndex +1 // 2️⃣ 如果原供应商有 sortIndex,需要将后续所有供应商的 sortIndex +1
@@ -402,7 +405,6 @@ function App() {
> >
CC Switch CC Switch
</a> </a>
<div className="h-5 w-[1px] bg-black/10 dark:bg-white/15" />
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
@@ -468,39 +470,24 @@ function App() {
<> <>
<AppSwitcher activeApp={activeApp} onSwitch={setActiveApp} /> <AppSwitcher activeApp={activeApp} onSwitch={setActiveApp} />
<div className="h-8 w-[1px] bg-black/10 dark:bg-white/10 mx-1" />
<div className="glass p-1 rounded-xl flex items-center gap-1"> <div className="glass p-1 rounded-xl flex items-center gap-1">
<Button <Button
variant="ghost" variant="ghost"
size="sm" size="sm"
onClick={() => setCurrentView("prompts")} onClick={() => setCurrentView("skills")}
className="text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5" className={cn(
title={t("prompts.manage")} "text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5",
"transition-all duration-200 ease-in-out overflow-hidden",
isClaudeApp
? "opacity-100 w-8 scale-100 px-2"
: "opacity-0 w-0 scale-75 pointer-events-none px-0 -ml-1",
)}
title={t("skills.manage")}
> >
<Book className="h-4 w-4" /> <Wrench className="h-4 w-4 flex-shrink-0" />
</Button> </Button>
{isClaudeApp && ( {/* TODO: Agents 功能开发中,暂时隐藏入口 */}
<Button {/* {isClaudeApp && (
variant="ghost"
size="sm"
onClick={() => setCurrentView("skills")}
className="text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5"
title={t("skills.manage")}
>
<Wrench className="h-4 w-4" />
</Button>
)}
<Button
variant="ghost"
size="sm"
onClick={() => setCurrentView("mcp")}
className="text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5"
title="MCP"
>
<Server className="h-4 w-4" />
</Button>
{isClaudeApp && (
<Button <Button
variant="ghost" variant="ghost"
size="sm" size="sm"
@@ -510,7 +497,25 @@ function App() {
> >
<Bot className="h-4 w-4" /> <Bot className="h-4 w-4" />
</Button> </Button>
)} )} */}
<Button
variant="ghost"
size="sm"
onClick={() => setCurrentView("prompts")}
className="text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5"
title={t("prompts.manage")}
>
<Book className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setCurrentView("mcp")}
className="text-muted-foreground hover:text-foreground hover:bg-black/5 dark:hover:bg-white/5"
title="MCP"
>
<Server className="h-4 w-4" />
</Button>
</div> </div>
<Button <Button