feat: add chat navigation bar close (#4019)
* feat(聊天导航): 新增关闭、置顶和置底按钮并更新图标 在聊天导航组件中新增了关闭、置顶和置底按钮,并更新了相关图标以提升用户体验。同时,添加了点击关闭按钮时隐藏导航的功能。 * feat(消息导航): 添加手动关闭状态以避免误触 在 ChatNavigation 组件中添加 `manuallyClosedUntil` 状态,用于在用户手动关闭导航后,1分钟内不响应鼠标靠近事件。这可以防止用户在操作时误触导航栏,提升用户体验。 * refactor(ChatNavigation): 重命名函数并添加滚动处理逻辑 重命名 handleChatNavigationClick 为 handleCloseChatNavigation 以提高代码可读性,并添加 handleScrollToTop 和 handleScrollToBottom 函数以处理滚动逻辑 * fix: 修复滚动到顶部时位置不正确的问题 将 `scrollToTop` 函数中的 `top` 值从 `0` 改为 `-container.scrollHeight`,以确保滚动到顶部时位置正确 * docs(i18n): 添加新的翻译字符串以支持更多操作 在多个语言文件中添加了“回到顶部”、“回到底部”和“关闭”的翻译字符串,以支持更多用户界面操作。 * refactor: 移除未使用的变量以简化代码 ``` 解释: - **类型**: `refactor`,因为这是代码重构,移除了未使用的变量,没有改变功能行为。 - **描述**: 移除了未使用的变量以简化代码,符合简洁和可维护性的原则。
This commit is contained in:
parent
a90be7e83f
commit
8b9929cc7b
@ -150,7 +150,10 @@
|
||||
"history": "Chat History",
|
||||
"last": "Already at the last message",
|
||||
"next": "Next Message",
|
||||
"prev": "Previous Message"
|
||||
"prev": "Previous Message",
|
||||
"top": "Back to top",
|
||||
"bottom": "Back to bottom",
|
||||
"close": "Close"
|
||||
},
|
||||
"resend": "Resend",
|
||||
"save": "Save",
|
||||
|
||||
@ -150,7 +150,10 @@
|
||||
"history": "チャット履歴",
|
||||
"last": "最後のメッセージです",
|
||||
"next": "次のメッセージ",
|
||||
"prev": "前のメッセージ"
|
||||
"prev": "前のメッセージ",
|
||||
"top": "トップに戻る",
|
||||
"bottom": "下部に戻る",
|
||||
"close": "閉じる"
|
||||
},
|
||||
"resend": "再送信",
|
||||
"save": "保存",
|
||||
|
||||
@ -150,7 +150,10 @@
|
||||
"history": "История чата",
|
||||
"last": "Уже последнее сообщение",
|
||||
"next": "Следующее сообщение",
|
||||
"prev": "Предыдущее сообщение"
|
||||
"prev": "Предыдущее сообщение",
|
||||
"top": "Вернуться наверх",
|
||||
"bottom": "Вернуться вниз",
|
||||
"close": "Закрыть"
|
||||
},
|
||||
"resend": "Переотправить",
|
||||
"save": "Сохранить",
|
||||
|
||||
@ -150,7 +150,10 @@
|
||||
"history": "聊天历史",
|
||||
"last": "已经是最后一条消息",
|
||||
"next": "下一条消息",
|
||||
"prev": "上一条消息"
|
||||
"prev": "上一条消息",
|
||||
"top": "回到顶部",
|
||||
"bottom": "回到底部",
|
||||
"close": "关闭"
|
||||
},
|
||||
"resend": "重新发送",
|
||||
"save": "保存",
|
||||
|
||||
@ -150,7 +150,10 @@
|
||||
"history": "聊天歷史",
|
||||
"last": "已經是最後一條訊息",
|
||||
"next": "下一條訊息",
|
||||
"prev": "上一條訊息"
|
||||
"prev": "上一條訊息",
|
||||
"top": "回到頂部",
|
||||
"bottom": "回到底部",
|
||||
"close": "關閉"
|
||||
},
|
||||
"resend": "重新傳送",
|
||||
"save": "儲存",
|
||||
|
||||
@ -130,7 +130,10 @@
|
||||
"first": "Ήδη το πρώτο μήνυμα",
|
||||
"last": "Ήδη το τελευταίο μήνυμα",
|
||||
"next": "Επόμενο μήνυμα",
|
||||
"prev": "Προηγούμενο μήνυμα"
|
||||
"prev": "Προηγούμενο μήνυμα",
|
||||
"top": "Επιστροφή στην κορυφή",
|
||||
"bottom": "Επιστροφή στο κάτω μέρος",
|
||||
"close": "Κλείσιμο"
|
||||
},
|
||||
"resend": "Ξαναστείλε",
|
||||
"save": "Αποθήκευση",
|
||||
|
||||
@ -130,7 +130,10 @@
|
||||
"first": "Ya es el primer mensaje",
|
||||
"last": "Ya es el último mensaje",
|
||||
"next": "Siguiente mensaje",
|
||||
"prev": "Mensaje anterior"
|
||||
"prev": "Mensaje anterior",
|
||||
"top": "Volver arriba",
|
||||
"bottom": "Volver abajo",
|
||||
"close": "Cerrar"
|
||||
},
|
||||
"resend": "Reenviar",
|
||||
"save": "Guardar",
|
||||
|
||||
@ -130,7 +130,10 @@
|
||||
"first": "Déjà premier message",
|
||||
"last": "Déjà dernier message",
|
||||
"next": "Prochain message",
|
||||
"prev": "Précédent message"
|
||||
"prev": "Précédent message",
|
||||
"top": "Retour en haut",
|
||||
"bottom": "Retour en bas",
|
||||
"close": "Fermer"
|
||||
},
|
||||
"resend": "Réenvoyer",
|
||||
"save": "Enregistrer",
|
||||
|
||||
@ -130,7 +130,10 @@
|
||||
"first": "Esta é a primeira mensagem",
|
||||
"last": "Esta é a última mensagem",
|
||||
"next": "Próxima mensagem",
|
||||
"prev": "Mensagem anterior"
|
||||
"prev": "Mensagem anterior",
|
||||
"top": "Voltar ao topo",
|
||||
"bottom": "Voltar ao fundo",
|
||||
"close": "Fechar"
|
||||
},
|
||||
"resend": "Reenviar",
|
||||
"save": "Salvar",
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
import { DownOutlined, HistoryOutlined, UpOutlined } from '@ant-design/icons'
|
||||
import {
|
||||
ArrowDownOutlined,
|
||||
ArrowUpOutlined,
|
||||
CloseOutlined,
|
||||
HistoryOutlined,
|
||||
VerticalAlignBottomOutlined,
|
||||
VerticalAlignTopOutlined
|
||||
} from '@ant-design/icons'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { RootState } from '@renderer/store'
|
||||
import { selectCurrentTopicId } from '@renderer/store/messages'
|
||||
@ -20,6 +27,7 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
const [isNearButtons, setIsNearButtons] = useState(false)
|
||||
const [hideTimer, setHideTimer] = useState<NodeJS.Timeout | null>(null)
|
||||
const [showChatHistory, setShowChatHistory] = useState(false)
|
||||
const [manuallyClosedUntil, setManuallyClosedUntil] = useState<number | null>(null)
|
||||
const currentTopicId = useSelector((state: RootState) => selectCurrentTopicId(state))
|
||||
const lastMoveTime = useRef(0)
|
||||
const { topicPosition, showTopics } = useSettings()
|
||||
@ -44,6 +52,10 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
|
||||
// Handle mouse entering button area
|
||||
const handleMouseEnter = useCallback(() => {
|
||||
if (manuallyClosedUntil && Date.now() < manuallyClosedUntil) {
|
||||
return
|
||||
}
|
||||
|
||||
setIsNearButtons(true)
|
||||
setIsVisible(true)
|
||||
|
||||
@ -52,7 +64,7 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
clearTimeout(hideTimer)
|
||||
setHideTimer(null)
|
||||
}
|
||||
}, [hideTimer])
|
||||
}, [hideTimer, manuallyClosedUntil])
|
||||
|
||||
// Handle mouse leaving button area
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
@ -97,7 +109,7 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
|
||||
const scrollToTop = () => {
|
||||
const container = document.getElementById(containerId)
|
||||
container && container.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
container && container.scrollTo({ top: -container.scrollHeight, behavior: 'smooth' })
|
||||
}
|
||||
|
||||
const scrollToBottom = () => {
|
||||
@ -148,6 +160,23 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 修改 handleCloseChatNavigation 函数
|
||||
const handleCloseChatNavigation = () => {
|
||||
setIsVisible(false)
|
||||
// 设置手动关闭状态,1分钟内不响应鼠标靠近事件
|
||||
setManuallyClosedUntil(Date.now() + 60000) // 60000毫秒 = 1分钟
|
||||
}
|
||||
|
||||
const handleScrollToTop = () => {
|
||||
resetHideTimer()
|
||||
scrollToTop()
|
||||
}
|
||||
|
||||
const handleScrollToBottom = () => {
|
||||
resetHideTimer()
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
const handleNextMessage = () => {
|
||||
resetHideTimer()
|
||||
const userMessages = findUserMessages()
|
||||
@ -216,6 +245,11 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
|
||||
// Throttled mouse move handler to improve performance
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
// 如果在手动关闭期间,不响应鼠标移动事件
|
||||
if (manuallyClosedUntil && Date.now() < manuallyClosedUntil) {
|
||||
return
|
||||
}
|
||||
|
||||
// Throttle mouse move to every 50ms for performance
|
||||
const now = Date.now()
|
||||
if (now - lastMoveTime.current < 50) return
|
||||
@ -262,16 +296,43 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
clearTimeout(hideTimer)
|
||||
}
|
||||
}
|
||||
}, [containerId, hideTimer, resetHideTimer, isNearButtons, handleMouseEnter, handleMouseLeave, showRightTopics])
|
||||
}, [
|
||||
containerId,
|
||||
hideTimer,
|
||||
resetHideTimer,
|
||||
isNearButtons,
|
||||
handleMouseEnter,
|
||||
handleMouseLeave,
|
||||
showRightTopics,
|
||||
manuallyClosedUntil
|
||||
])
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavigationContainer $isVisible={isVisible} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
|
||||
<ButtonGroup>
|
||||
<Tooltip title={t('chat.navigation.close')} placement="left">
|
||||
<NavigationButton
|
||||
type="text"
|
||||
icon={<CloseOutlined />}
|
||||
onClick={handleCloseChatNavigation}
|
||||
aria-label={t('chat.navigation.close')}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Divider />
|
||||
<Tooltip title={t('chat.navigation.top')} placement="left">
|
||||
<NavigationButton
|
||||
type="text"
|
||||
icon={<VerticalAlignTopOutlined />}
|
||||
onClick={handleScrollToTop}
|
||||
aria-label={t('chat.navigation.top')}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Divider />
|
||||
<Tooltip title={t('chat.navigation.prev')} placement="left">
|
||||
<NavigationButton
|
||||
type="text"
|
||||
icon={<UpOutlined />}
|
||||
icon={<ArrowUpOutlined />}
|
||||
onClick={handlePrevMessage}
|
||||
aria-label={t('chat.navigation.prev')}
|
||||
/>
|
||||
@ -280,12 +341,21 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
|
||||
<Tooltip title={t('chat.navigation.next')} placement="left">
|
||||
<NavigationButton
|
||||
type="text"
|
||||
icon={<DownOutlined />}
|
||||
icon={<ArrowDownOutlined />}
|
||||
onClick={handleNextMessage}
|
||||
aria-label={t('chat.navigation.next')}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Divider />
|
||||
<Tooltip title={t('chat.navigation.bottom')} placement="left">
|
||||
<NavigationButton
|
||||
type="text"
|
||||
icon={<VerticalAlignBottomOutlined />}
|
||||
onClick={handleScrollToBottom}
|
||||
aria-label={t('chat.navigation.bottom')}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Divider />
|
||||
<Tooltip title={t('chat.navigation.history')} placement="left">
|
||||
<NavigationButton
|
||||
type="text"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user