mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-06 21:35:52 +08:00
Add smooth animations to SessionsTab and Sessions components
- Replace static conditional rendering with Framer Motion animations for no-agent and session states - Animate session list items with staggered entrance and exit transitions - Add loading spinner animation with fade effect - Apply motion to session creation button with delayed entrance
This commit is contained in:
parent
1c813aa6c3
commit
6c233fef9f
@ -1,4 +1,5 @@
|
|||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
|
import { AnimatePresence,motion } from 'framer-motion'
|
||||||
import { FC, memo } from 'react'
|
import { FC, memo } from 'react'
|
||||||
|
|
||||||
import Sessions from './components/Sessions'
|
import Sessions from './components/Sessions'
|
||||||
@ -9,14 +10,29 @@ const SessionsTab: FC<SessionsTabProps> = () => {
|
|||||||
const { chat } = useRuntime()
|
const { chat } = useRuntime()
|
||||||
const { activeAgentId } = chat
|
const { activeAgentId } = chat
|
||||||
|
|
||||||
if (!activeAgentId) {
|
|
||||||
return <div> No active agent.</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<AnimatePresence mode="wait">
|
||||||
<Sessions agentId={activeAgentId} />
|
{!activeAgentId ? (
|
||||||
</>
|
<motion.div
|
||||||
|
key="no-agent"
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -10 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
className="flex h-full items-center justify-center text-foreground-500">
|
||||||
|
No active agent.
|
||||||
|
</motion.div>
|
||||||
|
) : (
|
||||||
|
<motion.div
|
||||||
|
key={activeAgentId}
|
||||||
|
initial={{ opacity: 0, x: 20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
exit={{ opacity: 0, x: -20 }}
|
||||||
|
transition={{ duration: 0.3, ease: 'easeOut' }}>
|
||||||
|
<Sessions agentId={activeAgentId} />
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { SessionModal } from '@renderer/components/Popups/agent/SessionModal'
|
|||||||
import { useSessions } from '@renderer/hooks/agents/useSessions'
|
import { useSessions } from '@renderer/hooks/agents/useSessions'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setActiveSessionIdAction, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
|
import { setActiveSessionIdAction, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
|
||||||
|
import { AnimatePresence,motion } from 'framer-motion'
|
||||||
import { Plus } from 'lucide-react'
|
import { Plus } from 'lucide-react'
|
||||||
import { memo, useCallback } from 'react'
|
import { memo, useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -28,36 +29,63 @@ const Sessions: React.FC<SessionsProps> = ({ agentId }) => {
|
|||||||
[dispatch]
|
[dispatch]
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isLoading) return <Spinner />
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
className="flex h-full items-center justify-center">
|
||||||
|
<Spinner size="lg" />
|
||||||
|
</motion.div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// if (error) return
|
// if (error) return
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="agents-tab h-full w-full p-2">
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
className="agents-tab h-full w-full p-2">
|
||||||
{/* TODO: Add session button */}
|
{/* TODO: Add session button */}
|
||||||
<SessionModal
|
<motion.div
|
||||||
agentId={agentId}
|
initial={{ opacity: 0, y: -10 }}
|
||||||
trigger={{
|
animate={{ opacity: 1, y: 0 }}
|
||||||
content: (
|
transition={{ duration: 0.2, delay: 0.1 }}>
|
||||||
<Button
|
<SessionModal
|
||||||
onPress={(e) => e.continuePropagation()}
|
|
||||||
className="mb-2 w-full justify-start bg-transparent text-foreground-500 hover:bg-accent">
|
|
||||||
<Plus size={16} className="mr-1 shrink-0" />
|
|
||||||
{t('agent.session.add.title')}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{sessions.map((session) => (
|
|
||||||
<SessionItem
|
|
||||||
key={session.id}
|
|
||||||
session={session}
|
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
onDelete={() => deleteSession(session.id)}
|
trigger={{
|
||||||
onPress={() => setActiveSessionId(agentId, session.id)}
|
content: (
|
||||||
|
<Button
|
||||||
|
onPress={(e) => e.continuePropagation()}
|
||||||
|
className="mb-2 w-full justify-start bg-transparent text-foreground-500 hover:bg-accent">
|
||||||
|
<Plus size={16} className="mr-1 shrink-0" />
|
||||||
|
{t('agent.session.add.title')}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
</motion.div>
|
||||||
</div>
|
<AnimatePresence>
|
||||||
|
{sessions.map((session, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={session.id}
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
exit={{ opacity: 0, x: 20, transition: { duration: 0.2 } }}
|
||||||
|
transition={{ duration: 0.3, delay: index * 0.05 }}>
|
||||||
|
<SessionItem
|
||||||
|
session={session}
|
||||||
|
agentId={agentId}
|
||||||
|
onDelete={() => deleteSession(session.id)}
|
||||||
|
onPress={() => setActiveSessionId(agentId, session.id)}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
|
</motion.div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user