refactor: Centralize emoji detection utility and improve avatar rendering
This commit is contained in:
parent
92ab67eb3d
commit
efa9c6c546
@ -4,15 +4,15 @@ import ImageStorage from '@renderer/services/ImageStorage'
|
||||
import { useAppDispatch } from '@renderer/store'
|
||||
import { setAvatar } from '@renderer/store/runtime'
|
||||
import { setUserName } from '@renderer/store/settings'
|
||||
import { compressImage } from '@renderer/utils'
|
||||
import { Avatar , Input, Modal, Popover, Upload, Dropdown } from 'antd'
|
||||
import { compressImage, isEmoji } from '@renderer/utils'
|
||||
import { Avatar, Dropdown, Input, Modal, Popover, Upload } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import EmojiPicker from '../EmojiPicker'
|
||||
import { Center, HStack, VStack } from '../Layout'
|
||||
import { TopView } from '../TopView'
|
||||
import EmojiPicker from '../EmojiPicker'
|
||||
|
||||
interface Props {
|
||||
resolve: (data: any) => void
|
||||
@ -51,12 +51,6 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
}
|
||||
}
|
||||
|
||||
// modify the judgment function, more accurately detect Emoji
|
||||
const isEmoji = (str: string) => {
|
||||
// check if it is a string and is not base64 or URL format
|
||||
return str && typeof str === 'string' && !str.startsWith('data:') && !str.startsWith('http');
|
||||
}
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: 'upload',
|
||||
@ -88,11 +82,12 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
{
|
||||
key: 'emoji',
|
||||
label: (
|
||||
<div onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setEmojiPickerOpen(true)
|
||||
setDropdownOpen(false)
|
||||
}}>
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setEmojiPickerOpen(true)
|
||||
setDropdownOpen(false)
|
||||
}}>
|
||||
{t('settings.general.emoji_picker')}
|
||||
</div>
|
||||
)
|
||||
@ -111,8 +106,8 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
centered>
|
||||
<Center mt="30px">
|
||||
<VStack alignItems="center" gap="10px">
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
trigger={['click']}
|
||||
open={dropdownOpen}
|
||||
align={{ offset: [0, 4] }}
|
||||
@ -134,11 +129,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
}
|
||||
}}
|
||||
placement="bottom">
|
||||
{isEmoji(avatar) ? (
|
||||
<EmojiAvatar>{avatar}</EmojiAvatar>
|
||||
) : (
|
||||
<UserAvatar src={avatar} />
|
||||
)}
|
||||
{isEmoji(avatar) ? <EmojiAvatar>{avatar}</EmojiAvatar> : <UserAvatar src={avatar} />}
|
||||
</Popover>
|
||||
</Dropdown>
|
||||
</VStack>
|
||||
@ -147,7 +138,7 @@ const PopupContainer: React.FC<Props> = ({ resolve }) => {
|
||||
<Input
|
||||
placeholder={t('settings.general.user_name.placeholder')}
|
||||
value={userName}
|
||||
onChange={(e) => dispatch(setUserName(e.target.value))}
|
||||
onChange={(e) => dispatch(setUserName(e.target.value.trim()))}
|
||||
style={{ flex: 1, textAlign: 'center', width: '100%' }}
|
||||
maxLength={30}
|
||||
/>
|
||||
@ -201,4 +192,4 @@ export default class UserPopup {
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import useAvatar from '@renderer/hooks/useAvatar'
|
||||
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||
import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { isEmoji } from '@renderer/utils'
|
||||
import type { MenuProps } from 'antd'
|
||||
import { Tooltip } from 'antd'
|
||||
import { Avatar } from 'antd'
|
||||
@ -57,10 +58,6 @@ const Sidebar: FC = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const isEmoji = (str: string) => {
|
||||
return str && typeof str === 'string' && !str.startsWith('data:') && !str.startsWith('http');
|
||||
}
|
||||
|
||||
return (
|
||||
<Container
|
||||
id="app-sidebar"
|
||||
@ -69,7 +66,7 @@ const Sidebar: FC = () => {
|
||||
zIndex: minappShow ? 10000 : 'initial'
|
||||
}}>
|
||||
{isEmoji(avatar) ? (
|
||||
<EmojiAvatarSidebar onClick={onEditUser}>{avatar}</EmojiAvatarSidebar>
|
||||
<EmojiAvatar onClick={onEditUser}>{avatar}</EmojiAvatar>
|
||||
) : (
|
||||
<AvatarImg src={avatar || UserAvatar} draggable={false} className="nodrag" onClick={onEditUser} />
|
||||
)}
|
||||
@ -229,7 +226,7 @@ const AvatarImg = styled(Avatar)`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
const EmojiAvatarSidebar = styled.div`
|
||||
const EmojiAvatar = styled.div`
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
background-color: var(--color-background-soft);
|
||||
@ -242,6 +239,7 @@ const EmojiAvatarSidebar = styled.div`
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
-webkit-app-region: none;
|
||||
border: 0.5px solid var(--color-border);
|
||||
`
|
||||
|
||||
const MainMenusContainer = styled.div`
|
||||
|
||||
@ -8,17 +8,13 @@ import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings'
|
||||
import { getMessageModelId } from '@renderer/services/MessagesService'
|
||||
import { getModelName } from '@renderer/services/ModelService'
|
||||
import { Assistant, Message, Model } from '@renderer/types'
|
||||
import { firstLetter, removeLeadingEmoji } from '@renderer/utils'
|
||||
import { firstLetter, isEmoji, removeLeadingEmoji } from '@renderer/utils'
|
||||
import { Avatar } from 'antd'
|
||||
import dayjs from 'dayjs'
|
||||
import { CSSProperties, FC, memo, useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const isEmoji = (str: string) => {
|
||||
return str && typeof str === 'string' && !str.startsWith('data:') && !str.startsWith('http');
|
||||
}
|
||||
|
||||
interface Props {
|
||||
message: Message
|
||||
assistant: Assistant
|
||||
|
||||
@ -123,6 +123,19 @@ export function getLeadingEmoji(str: string): string {
|
||||
return match ? match[0] : ''
|
||||
}
|
||||
|
||||
export function isEmoji(str: string) {
|
||||
if (str.startsWith('data:')) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (str.startsWith('http')) {
|
||||
return false
|
||||
}
|
||||
|
||||
const emojiRegex = /^(\p{Emoji_Presentation}|\p{Emoji}\uFE0F)+/u
|
||||
return str.match(emojiRegex)
|
||||
}
|
||||
|
||||
export function isFreeModel(model: Model) {
|
||||
return (model.id + model.name).toLocaleLowerCase().includes('free')
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user