mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 18:10:26 +08:00
🔧 refactor(UI): Optimize MentionModelsButton with performance improvements and styling updates
- Add useCallback for togglePin and handleModelSelect to prevent unnecessary re-renders - Refactor dropdown menu styling with more specific CSS scoping - Simplify dropdown open/close logic - Improve performance by memoizing function dependencies - Adjust dropdown overlay styling and animation
This commit is contained in:
parent
a8451b7c3d
commit
d714a53dc6
@ -8,7 +8,7 @@ import { getModelUniqId } from '@renderer/services/ModelService'
|
|||||||
import { Model, Provider } from '@renderer/types'
|
import { Model, Provider } from '@renderer/types'
|
||||||
import { Avatar, Dropdown, Tooltip } from 'antd'
|
import { Avatar, Dropdown, Tooltip } from 'antd'
|
||||||
import { first, sortBy } from 'lodash'
|
import { first, sortBy } from 'lodash'
|
||||||
import { FC, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
import { FC, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled, { createGlobalStyle } from 'styled-components'
|
import styled, { createGlobalStyle } from 'styled-components'
|
||||||
|
|
||||||
@ -37,23 +37,29 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
itemRefs.current[index] = el
|
itemRefs.current[index] = el
|
||||||
}
|
}
|
||||||
|
|
||||||
const togglePin = async (modelId: string) => {
|
const togglePin = useCallback(
|
||||||
const newPinnedModels = pinnedModels.includes(modelId)
|
async (modelId: string) => {
|
||||||
? pinnedModels.filter((id) => id !== modelId)
|
const newPinnedModels = pinnedModels.includes(modelId)
|
||||||
: [...pinnedModels, modelId]
|
? pinnedModels.filter((id) => id !== modelId)
|
||||||
|
: [...pinnedModels, modelId]
|
||||||
|
|
||||||
await db.settings.put({ id: 'pinned:models', value: newPinnedModels })
|
await db.settings.put({ id: 'pinned:models', value: newPinnedModels })
|
||||||
setPinnedModels(newPinnedModels)
|
setPinnedModels(newPinnedModels)
|
||||||
}
|
},
|
||||||
|
[pinnedModels]
|
||||||
|
)
|
||||||
|
|
||||||
const handleModelSelect = (model: Model) => {
|
const handleModelSelect = useCallback(
|
||||||
// Check if model is already selected
|
(model: Model) => {
|
||||||
if (mentionModels.some((selected) => getModelUniqId(selected) === getModelUniqId(model))) {
|
// Check if model is already selected
|
||||||
return
|
if (mentionModels.some((selected) => getModelUniqId(selected) === getModelUniqId(model))) {
|
||||||
}
|
return
|
||||||
onSelect(model, fromKeyboard)
|
}
|
||||||
setIsOpen(false)
|
onSelect(model, fromKeyboard)
|
||||||
}
|
setIsOpen(false)
|
||||||
|
},
|
||||||
|
[fromKeyboard, mentionModels, onSelect]
|
||||||
|
)
|
||||||
|
|
||||||
const modelMenuItems = useMemo(() => {
|
const modelMenuItems = useMemo(() => {
|
||||||
const items = providers
|
const items = providers
|
||||||
@ -161,7 +167,7 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
|
|
||||||
// Remove empty groups
|
// Remove empty groups
|
||||||
return items.filter((group) => group.children.length > 0)
|
return items.filter((group) => group.children.length > 0)
|
||||||
}, [providers, pinnedModels, t, onSelect, mentionModels, searchText])
|
}, [providers, pinnedModels, t, searchText, togglePin, handleModelSelect])
|
||||||
|
|
||||||
// Get flattened list of all model items
|
// Get flattened list of all model items
|
||||||
const flatModelItems = useMemo(() => {
|
const flatModelItems = useMemo(() => {
|
||||||
@ -345,14 +351,13 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
<>
|
<>
|
||||||
<DropdownMenuStyle />
|
<DropdownMenuStyle />
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
overlayStyle={{ marginBottom: 20 }}
|
||||||
dropdownRender={() => menu}
|
dropdownRender={() => menu}
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
setIsOpen(open)
|
setIsOpen(open)
|
||||||
if (open) {
|
open && setFromKeyboard(false) // Set fromKeyboard to false when opened by button click
|
||||||
setFromKeyboard(false) // Set fromKeyboard to false when opened by button click
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
overlayClassName="mention-models-dropdown">
|
overlayClassName="mention-models-dropdown">
|
||||||
<Tooltip placement="top" title={t('agents.edit.model.select.title')} arrow>
|
<Tooltip placement="top" title={t('agents.edit.model.select.title')} arrow>
|
||||||
@ -366,25 +371,27 @@ const MentionModelsButton: FC<Props> = ({ mentionModels, onMentionModel: onSelec
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DropdownMenuStyle = createGlobalStyle`
|
const DropdownMenuStyle = createGlobalStyle`
|
||||||
/* Apply background to all animation states */
|
/* 将样式限定在 mention-models-dropdown 类下 */
|
||||||
.ant-dropdown,
|
|
||||||
.ant-slide-up-enter .ant-dropdown-menu,
|
|
||||||
.ant-slide-up-appear .ant-dropdown-menu,
|
|
||||||
.ant-slide-up-leave .ant-dropdown-menu,
|
|
||||||
.ant-slide-up-enter-active .ant-dropdown-menu,
|
|
||||||
.ant-slide-up-appear-active .ant-dropdown-menu,
|
|
||||||
.ant-slide-up-leave-active .ant-dropdown-menu {
|
|
||||||
background: rgba(var(--color-base-rgb), 0.65) !important;
|
|
||||||
backdrop-filter: blur(35px) saturate(150%) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mention-models-dropdown {
|
.mention-models-dropdown {
|
||||||
&.ant-dropdown {
|
&.ant-dropdown {
|
||||||
|
background: rgba(var(--color-base-rgb), 0.65) !important;
|
||||||
|
backdrop-filter: blur(35px) saturate(150%) !important;
|
||||||
animation-duration: 0.15s !important;
|
animation-duration: 0.15s !important;
|
||||||
margin-top: 4px;
|
}
|
||||||
|
|
||||||
|
/* 移动其他样式到 mention-models-dropdown 类下 */
|
||||||
|
.ant-slide-up-enter .ant-dropdown-menu,
|
||||||
|
.ant-slide-up-appear .ant-dropdown-menu,
|
||||||
|
.ant-slide-up-leave .ant-dropdown-menu,
|
||||||
|
.ant-slide-up-enter-active .ant-dropdown-menu,
|
||||||
|
.ant-slide-up-appear-active .ant-dropdown-menu,
|
||||||
|
.ant-slide-up-leave-active .ant-dropdown-menu {
|
||||||
|
background: rgba(var(--color-base-rgb), 0.65) !important;
|
||||||
|
backdrop-filter: blur(35px) saturate(150%) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-dropdown-menu {
|
.ant-dropdown-menu {
|
||||||
|
/* 保持原有的下拉菜单样式,但限定在 mention-models-dropdown 类下 */
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@ -401,6 +408,7 @@ const DropdownMenuStyle = createGlobalStyle`
|
|||||||
transform-origin: top;
|
transform-origin: top;
|
||||||
will-change: transform, opacity;
|
will-change: transform, opacity;
|
||||||
transition: all 0.15s cubic-bezier(0.4, 0.0, 0.2, 1);
|
transition: all 0.15s cubic-bezier(0.4, 0.0, 0.2, 1);
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
&.no-scrollbar {
|
&.no-scrollbar {
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user