mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-25 03:10:08 +08:00
fix: update current topic id and support EmojiAvatar for ChatFlowHistory (#5861)
* fix: update current topic id for ChatFlowHistory to work * refactor: set current topic id early in loadTopicMessagesThunk * refactor: extract EmojiAvatar * fix: style
This commit is contained in:
parent
9262f92bff
commit
c7a15d291e
52
src/renderer/src/components/Avatar/EmojiAvatar.tsx
Normal file
52
src/renderer/src/components/Avatar/EmojiAvatar.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React, { memo } from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
interface EmojiAvatarProps {
|
||||
children: string
|
||||
size?: number
|
||||
fontSize?: number
|
||||
onClick?: React.MouseEventHandler<HTMLDivElement>
|
||||
className?: string
|
||||
style?: React.CSSProperties
|
||||
}
|
||||
|
||||
const EmojiAvatar = ({
|
||||
ref,
|
||||
children,
|
||||
size = 31,
|
||||
fontSize,
|
||||
onClick,
|
||||
className,
|
||||
style
|
||||
}: EmojiAvatarProps & { ref?: React.RefObject<HTMLDivElement | null> }) => (
|
||||
<StyledEmojiAvatar
|
||||
ref={ref}
|
||||
$size={size}
|
||||
$fontSize={fontSize ?? size * 0.5}
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
style={style}>
|
||||
{children}
|
||||
</StyledEmojiAvatar>
|
||||
)
|
||||
|
||||
EmojiAvatar.displayName = 'EmojiAvatar'
|
||||
|
||||
const StyledEmojiAvatar = styled.div<{ $size: number; $fontSize: number }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--color-background-soft);
|
||||
border: 0.5px solid var(--color-border);
|
||||
border-radius: 20%;
|
||||
cursor: pointer;
|
||||
width: ${(props) => props.$size}px;
|
||||
height: ${(props) => props.$size}px;
|
||||
font-size: ${(props) => props.$fontSize}px;
|
||||
transition: opacity 0.3s ease;
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
`
|
||||
|
||||
export default memo(EmojiAvatar)
|
||||
@ -1,4 +1,5 @@
|
||||
import DefaultAvatar from '@renderer/assets/images/avatar.png'
|
||||
import EmojiAvatar from '@renderer/components/Avatar/EmojiAvatar'
|
||||
import useAvatar from '@renderer/hooks/useAvatar'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import ImageStorage from '@renderer/services/ImageStorage'
|
||||
@ -154,7 +155,13 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
}
|
||||
}}
|
||||
placement="bottom">
|
||||
{isEmoji(avatar) ? <EmojiAvatar>{avatar}</EmojiAvatar> : <UserAvatar src={avatar} />}
|
||||
{isEmoji(avatar) ? (
|
||||
<EmojiAvatar size={80} fontSize={40}>
|
||||
{avatar}
|
||||
</EmojiAvatar>
|
||||
) : (
|
||||
<UserAvatar src={avatar} />
|
||||
)}
|
||||
</Popover>
|
||||
</Dropdown>
|
||||
</VStack>
|
||||
@ -182,23 +189,6 @@ const UserAvatar = styled(Avatar)`
|
||||
}
|
||||
`
|
||||
|
||||
const EmojiAvatar = styled.div`
|
||||
cursor: pointer;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 20%;
|
||||
background-color: var(--color-background-soft);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40px;
|
||||
transition: opacity 0.3s ease;
|
||||
border: 0.5px solid var(--color-border);
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
`
|
||||
|
||||
export default class UserPopup {
|
||||
static topviewId = 0
|
||||
static hide() {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import EmojiAvatar from '@renderer/components/Avatar/EmojiAvatar'
|
||||
import { isMac } from '@renderer/config/constant'
|
||||
import { AppLogo, UserAvatar } from '@renderer/config/env'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
@ -70,7 +71,9 @@ const Sidebar: FC = () => {
|
||||
return (
|
||||
<Container id="app-sidebar" style={{ backgroundColor, zIndex: minappShow ? 10000 : 'initial' }}>
|
||||
{isEmoji(avatar) ? (
|
||||
<EmojiAvatar onClick={onEditUser}>{avatar}</EmojiAvatar>
|
||||
<EmojiAvatar onClick={onEditUser} className="sidebar-avatar" size={31} fontSize={18}>
|
||||
{avatar}
|
||||
</EmojiAvatar>
|
||||
) : (
|
||||
<AvatarImg src={avatar || UserAvatar} draggable={false} className="nodrag" onClick={onEditUser} />
|
||||
)}
|
||||
@ -319,6 +322,12 @@ const Container = styled.div`
|
||||
height: ${isMac ? 'calc(100vh - var(--navbar-height))' : '100vh'};
|
||||
-webkit-app-region: drag !important;
|
||||
margin-top: ${isMac ? 'var(--navbar-height)' : 0};
|
||||
|
||||
.sidebar-avatar {
|
||||
margin-bottom: ${isMac ? '12px' : '12px'};
|
||||
margin-top: ${isMac ? '0px' : '2px'};
|
||||
-webkit-app-region: none;
|
||||
}
|
||||
`
|
||||
|
||||
const AvatarImg = styled(Avatar)`
|
||||
@ -331,23 +340,6 @@ const AvatarImg = styled(Avatar)`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const EmojiAvatar = styled.div`
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
background-color: var(--color-background-soft);
|
||||
margin-bottom: ${isMac ? '12px' : '12px'};
|
||||
margin-top: ${isMac ? '0px' : '2px'};
|
||||
border-radius: 20%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
-webkit-app-region: none;
|
||||
border: 0.5px solid var(--color-border);
|
||||
font-size: 20px;
|
||||
`
|
||||
|
||||
const MainMenusContainer = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
import '@xyflow/react/dist/style.css'
|
||||
|
||||
import { RobotOutlined, UserOutlined } from '@ant-design/icons'
|
||||
import EmojiAvatar from '@renderer/components/Avatar/EmojiAvatar'
|
||||
import ModelAvatar from '@renderer/components/Avatar/ModelAvatar'
|
||||
import { getModelLogo } from '@renderer/config/models'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
import useAvatar from '@renderer/hooks/useAvatar'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
import { RootState } from '@renderer/store'
|
||||
import { selectMessagesForTopic } from '@renderer/store/newMessage'
|
||||
import { Model } from '@renderer/types'
|
||||
import { isEmoji } from '@renderer/utils'
|
||||
import { getMainTextContent } from '@renderer/utils/messageUtils/find'
|
||||
import { Controls, Handle, MiniMap, ReactFlow, ReactFlowProvider } from '@xyflow/react'
|
||||
import { Edge, Node, NodeTypes, Position, useEdgesState, useNodesState } from '@xyflow/react'
|
||||
@ -63,7 +66,11 @@ const CustomNode: FC<{ data: any }> = ({ data }) => {
|
||||
|
||||
// 用户头像
|
||||
if (data.userAvatar) {
|
||||
avatar = <Avatar src={data.userAvatar} alt={title} />
|
||||
if (isEmoji(data.userAvatar)) {
|
||||
avatar = <EmojiAvatar size={32}>{data.userAvatar}</EmojiAvatar>
|
||||
} else {
|
||||
avatar = <Avatar src={data.userAvatar} alt={title} />
|
||||
}
|
||||
} else {
|
||||
avatar = <Avatar icon={<UserOutlined />} style={{ backgroundColor: 'var(--color-info)' }} />
|
||||
}
|
||||
@ -221,7 +228,7 @@ const ChatFlowHistory: FC<ChatFlowHistoryProps> = ({ conversationId }) => {
|
||||
)
|
||||
|
||||
// 获取用户头像
|
||||
const userAvatar = useSelector((state: RootState) => state.runtime.avatar)
|
||||
const userAvatar = useAvatar()
|
||||
|
||||
// 消息过滤
|
||||
const { userMessages, assistantMessages } = useMemo(() => {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { DownOutlined } from '@ant-design/icons'
|
||||
import EmojiAvatar from '@renderer/components/Avatar/EmojiAvatar'
|
||||
import { APP_NAME, AppLogo, isLocalAi } from '@renderer/config/env'
|
||||
import { getModelLogo } from '@renderer/config/models'
|
||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||
@ -16,6 +17,7 @@ import { Avatar } from 'antd'
|
||||
import { type FC, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
interface MessageLineProps {
|
||||
messages: Message[]
|
||||
}
|
||||
@ -230,7 +232,15 @@ const MessageAnchorLine: FC<MessageLineProps> = ({ messages }) => {
|
||||
) : (
|
||||
<>
|
||||
{isEmoji(avatar) ? (
|
||||
<EmojiAvatar size={size}>{avatar}</EmojiAvatar>
|
||||
<EmojiAvatar
|
||||
size={size}
|
||||
fontSize={size * 0.6}
|
||||
style={{
|
||||
cursor: 'default',
|
||||
pointerEvents: 'none'
|
||||
}}>
|
||||
{avatar}
|
||||
</EmojiAvatar>
|
||||
) : (
|
||||
<Avatar src={avatar} size={size} />
|
||||
)}
|
||||
@ -314,16 +324,4 @@ const MessageItemContent = styled.div`
|
||||
max-width: 200px;
|
||||
`
|
||||
|
||||
const EmojiAvatar = styled.div<{ size: number }>`
|
||||
width: ${(props) => props.size}px;
|
||||
height: ${(props) => props.size}px;
|
||||
background-color: var(--color-background-soft);
|
||||
border-radius: 20%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: ${(props) => props.size * 0.6}px;
|
||||
border: 0.5px solid var(--color-border);
|
||||
`
|
||||
|
||||
export default MessageAnchorLine
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import EmojiAvatar from '@renderer/components/Avatar/EmojiAvatar'
|
||||
import UserPopup from '@renderer/components/Popups/UserPopup'
|
||||
import { APP_NAME, AppLogo, isLocalAi } from '@renderer/config/env'
|
||||
import { getModelLogo } from '@renderer/config/models'
|
||||
@ -87,7 +88,9 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message }) => {
|
||||
) : (
|
||||
<>
|
||||
{isEmoji(avatar) ? (
|
||||
<EmojiAvatar onClick={() => UserPopup.show()}>{avatar}</EmojiAvatar>
|
||||
<EmojiAvatar onClick={() => UserPopup.show()} size={35} fontSize={20}>
|
||||
{avatar}
|
||||
</EmojiAvatar>
|
||||
) : (
|
||||
<Avatar
|
||||
src={avatar}
|
||||
@ -111,20 +114,6 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message }) => {
|
||||
|
||||
MessageHeader.displayName = 'MessageHeader'
|
||||
|
||||
const EmojiAvatar = styled.div`
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
background-color: var(--color-background-soft);
|
||||
border-radius: 20%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
border: 0.5px solid var(--color-border);
|
||||
font-size: 20px;
|
||||
`
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@ -726,6 +726,7 @@ export const loadTopicMessagesThunk =
|
||||
async (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState()
|
||||
const topicMessagesExist = !!state.messages.messageIdsByTopic[topicId]
|
||||
dispatch(newMessagesActions.setCurrentTopicId(topicId))
|
||||
|
||||
if (topicMessagesExist && !forceReload) {
|
||||
return
|
||||
|
||||
Loading…
Reference in New Issue
Block a user