From 3f656ab2027fbc2afc4321441594909ab162685b Mon Sep 17 00:00:00 2001 From: FischLu Date: Fri, 14 Feb 2025 11:52:36 +0100 Subject: [PATCH] feat: implement select mode menu autoscroll for long mode lists --- .../home/Inputbar/MentionModelsButton.tsx | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/renderer/src/pages/home/Inputbar/MentionModelsButton.tsx b/src/renderer/src/pages/home/Inputbar/MentionModelsButton.tsx index 0358ca53b1..83be37411f 100644 --- a/src/renderer/src/pages/home/Inputbar/MentionModelsButton.tsx +++ b/src/renderer/src/pages/home/Inputbar/MentionModelsButton.tsx @@ -8,7 +8,7 @@ import { getModelUniqId } from '@renderer/services/ModelService' import { Model, Provider } from '@renderer/types' import { Avatar, Dropdown, Tooltip } from 'antd' import { first, sortBy } from 'lodash' -import { FC, useEffect, useMemo, useRef, useState } from 'react' +import { FC, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import styled, { createGlobalStyle } from 'styled-components' @@ -27,6 +27,11 @@ const MentionModelsButton: FC = ({ mentionModels, onMentionModel: onSelec const [isOpen, setIsOpen] = useState(false) const menuRef = useRef(null) const [searchText, setSearchText] = useState('') + const itemRefs = useRef>([]) + + const setItemRef = (index: number, el: HTMLDivElement | null) => { + itemRefs.current[index] = el + } const togglePin = async (modelId: string) => { const newPinnedModels = pinnedModels.includes(modelId) @@ -167,9 +172,17 @@ const MentionModelsButton: FC = ({ mentionModels, onMentionModel: onSelec loadPinnedModels() }, []) + // Scroll to the first menu item when the mode selection menu opens + useLayoutEffect(() => { + if (isOpen && flatModelItems.length > 0 && itemRefs.current[0]) { + itemRefs.current[0].scrollIntoView({ block: 'nearest' }) + } + }, [isOpen, flatModelItems]) + useEffect(() => { const showModelSelector = () => { dropdownRef.current?.click() + itemRefs.current = [] setIsOpen(true) setSelectedIndex(0) setSearchText('') @@ -180,10 +193,18 @@ const MentionModelsButton: FC = ({ mentionModels, onMentionModel: onSelec if (e.key === 'ArrowDown') { e.preventDefault() - setSelectedIndex((prev) => (prev < flatModelItems.length - 1 ? prev + 1 : 0)) + setSelectedIndex((prev) => { + const newIndex = prev < flatModelItems.length - 1 ? prev + 1 : 0 + itemRefs.current[newIndex]?.scrollIntoView({ block: 'nearest' }) + return newIndex + }) } else if (e.key === 'ArrowUp') { e.preventDefault() - setSelectedIndex((prev) => (prev > 0 ? prev - 1 : flatModelItems.length - 1)) + setSelectedIndex((prev) => { + const newIndex = prev > 0 ? prev - 1 : flatModelItems.length - 1 + itemRefs.current[newIndex]?.scrollIntoView({ block: 'nearest' }) + return newIndex + }) } else if (e.key === 'Enter') { e.preventDefault() if (selectedIndex >= 0 && selectedIndex < flatModelItems.length) { @@ -250,15 +271,20 @@ const MentionModelsButton: FC = ({ mentionModels, onMentionModel: onSelec
{group.label}
- {group.children.map((item, idx) => ( -
- {item.icon} - {item.label} -
- ))} + {group.children.map((item, idx) => { + // calculate item global idx + const index = startIndex + idx + return ( +
setItemRef(index, el)} + className={`ant-dropdown-menu-item ${selectedIndex === index ? 'ant-dropdown-menu-item-selected' : ''}`} + onClick={item.onClick}> + {item.icon} + {item.label} +
+ ) + })}
)