mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-18 10:58:52 +08:00
feat(ui): add fade transition for view and panel switching
Add smooth fade animations when navigating between views (Settings, MCP, Skills, Prompts) and opening full-screen panels (Add/Edit Provider).
This commit is contained in:
+85
-71
@@ -299,78 +299,92 @@ function App() {
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
switch (currentView) {
|
||||
case "settings":
|
||||
return (
|
||||
<SettingsPage
|
||||
open={true}
|
||||
onOpenChange={() => setCurrentView("providers")}
|
||||
onImportSuccess={handleImportSuccess}
|
||||
/>
|
||||
);
|
||||
case "prompts":
|
||||
return (
|
||||
<PromptPanel
|
||||
ref={promptPanelRef}
|
||||
open={true}
|
||||
onOpenChange={() => setCurrentView("providers")}
|
||||
appId={activeApp}
|
||||
/>
|
||||
);
|
||||
case "skills":
|
||||
return (
|
||||
<SkillsPage
|
||||
ref={skillsPageRef}
|
||||
onClose={() => setCurrentView("providers")}
|
||||
initialApp={activeApp}
|
||||
/>
|
||||
);
|
||||
case "mcp":
|
||||
return (
|
||||
<UnifiedMcpPanel
|
||||
ref={mcpPanelRef}
|
||||
onOpenChange={() => setCurrentView("providers")}
|
||||
/>
|
||||
);
|
||||
case "agents":
|
||||
return <AgentsPanel onOpenChange={() => setCurrentView("providers")} />;
|
||||
default:
|
||||
return (
|
||||
<div className="mx-auto max-w-[56rem] px-5 flex flex-col h-[calc(100vh-8rem)] overflow-hidden">
|
||||
{/* 独立滚动容器 - 解决 Linux/Ubuntu 下 DndContext 与滚轮事件冲突 */}
|
||||
<div className="flex-1 px-1 pb-12 overflow-x-hidden overflow-y-auto">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={activeApp}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
className="space-y-4"
|
||||
>
|
||||
<ProviderList
|
||||
providers={providers}
|
||||
currentProviderId={currentProviderId}
|
||||
appId={activeApp}
|
||||
isLoading={isLoading}
|
||||
isProxyRunning={isProxyRunning}
|
||||
isProxyTakeover={
|
||||
isProxyRunning && isCurrentAppTakeoverActive
|
||||
}
|
||||
onSwitch={switchProvider}
|
||||
onEdit={setEditingProvider}
|
||||
onDelete={setConfirmDelete}
|
||||
onDuplicate={handleDuplicateProvider}
|
||||
onConfigureUsage={setUsageProvider}
|
||||
onOpenWebsite={handleOpenWebsite}
|
||||
onCreate={() => setIsAddOpen(true)}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
const content = (() => {
|
||||
switch (currentView) {
|
||||
case "settings":
|
||||
return (
|
||||
<SettingsPage
|
||||
open={true}
|
||||
onOpenChange={() => setCurrentView("providers")}
|
||||
onImportSuccess={handleImportSuccess}
|
||||
/>
|
||||
);
|
||||
case "prompts":
|
||||
return (
|
||||
<PromptPanel
|
||||
ref={promptPanelRef}
|
||||
open={true}
|
||||
onOpenChange={() => setCurrentView("providers")}
|
||||
appId={activeApp}
|
||||
/>
|
||||
);
|
||||
case "skills":
|
||||
return (
|
||||
<SkillsPage
|
||||
ref={skillsPageRef}
|
||||
onClose={() => setCurrentView("providers")}
|
||||
initialApp={activeApp}
|
||||
/>
|
||||
);
|
||||
case "mcp":
|
||||
return (
|
||||
<UnifiedMcpPanel
|
||||
ref={mcpPanelRef}
|
||||
onOpenChange={() => setCurrentView("providers")}
|
||||
/>
|
||||
);
|
||||
case "agents":
|
||||
return <AgentsPanel onOpenChange={() => setCurrentView("providers")} />;
|
||||
default:
|
||||
return (
|
||||
<div className="mx-auto max-w-[56rem] px-5 flex flex-col h-[calc(100vh-8rem)] overflow-hidden">
|
||||
{/* 独立滚动容器 - 解决 Linux/Ubuntu 下 DndContext 与滚轮事件冲突 */}
|
||||
<div className="flex-1 overflow-y-auto overflow-x-hidden pb-12 px-1">
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={activeApp}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
className="space-y-4"
|
||||
>
|
||||
<ProviderList
|
||||
providers={providers}
|
||||
currentProviderId={currentProviderId}
|
||||
appId={activeApp}
|
||||
isLoading={isLoading}
|
||||
isProxyRunning={isProxyRunning}
|
||||
isProxyTakeover={isProxyRunning && isCurrentAppTakeoverActive}
|
||||
onSwitch={switchProvider}
|
||||
onEdit={setEditingProvider}
|
||||
onDelete={setConfirmDelete}
|
||||
onDuplicate={handleDuplicateProvider}
|
||||
onConfigureUsage={setUsageProvider}
|
||||
onOpenWebsite={handleOpenWebsite}
|
||||
onCreate={() => setIsAddOpen(true)}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
||||
return (
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={currentView}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
{content}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { motion } from "framer-motion";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
@@ -35,7 +36,10 @@ export const FullScreenPanel: React.FC<FullScreenPanelProps> = ({
|
||||
if (!isOpen) return null;
|
||||
|
||||
return createPortal(
|
||||
<div
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="fixed inset-0 z-[60] flex flex-col"
|
||||
style={{ backgroundColor: "hsl(var(--background))" }}
|
||||
>
|
||||
@@ -71,7 +75,7 @@ export const FullScreenPanel: React.FC<FullScreenPanelProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>,
|
||||
</motion.div>,
|
||||
document.body,
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user