feat: implement double-click navigation and click timer for breadcrumb items

This commit is contained in:
shiyu
2026-01-20 10:34:14 +08:00
parent d003e53a3a
commit a394ffa46b
@@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useRef, useState } from 'react';
import { Flex, Typography, Divider, Button, Space, Tooltip, Segmented, Breadcrumb, Input, theme, Dropdown } from 'antd'; import { Flex, Typography, Divider, Button, Space, Tooltip, Segmented, Breadcrumb, Input, theme, Dropdown } from 'antd';
import { ArrowUpOutlined, ArrowDownOutlined, ReloadOutlined, PlusOutlined, UploadOutlined, AppstoreOutlined, UnorderedListOutlined } from '@ant-design/icons'; import { ArrowUpOutlined, ArrowDownOutlined, ReloadOutlined, PlusOutlined, UploadOutlined, AppstoreOutlined, UnorderedListOutlined } from '@ant-design/icons';
import { Select } from 'antd'; import { Select } from 'antd';
@@ -41,9 +41,26 @@ export const Header: React.FC<HeaderProps> = ({
const { t } = useI18n(); const { t } = useI18n();
const [editingPath, setEditingPath] = useState(false); const [editingPath, setEditingPath] = useState(false);
const [pathInputValue, setPathInputValue] = useState(''); const [pathInputValue, setPathInputValue] = useState('');
const clickTimerRef = useRef<number | null>(null);
const pathEditorHeight = token.fontSizeSM * token.lineHeight + token.paddingXXS * 2; const pathEditorHeight = token.fontSizeSM * token.lineHeight + token.paddingXXS * 2;
const clearClickTimer = () => {
if (clickTimerRef.current !== null) {
window.clearTimeout(clickTimerRef.current);
clickTimerRef.current = null;
}
};
const scheduleNavigate = (nextPath: string) => {
clearClickTimer();
clickTimerRef.current = window.setTimeout(() => {
onNavigate(nextPath);
clickTimerRef.current = null;
}, 250);
};
const handlePathEdit = () => { const handlePathEdit = () => {
clearClickTimer();
setEditingPath(true); setEditingPath(true);
setPathInputValue(path); setPathInputValue(path);
}; };
@@ -61,6 +78,10 @@ export const Header: React.FC<HeaderProps> = ({
setPathInputValue(''); setPathInputValue('');
}; };
const handleBreadcrumbDoubleClick = () => {
handlePathEdit();
};
const renderBreadcrumb = () => { const renderBreadcrumb = () => {
if (editingPath) { if (editingPath) {
return ( return (
@@ -78,12 +99,12 @@ export const Header: React.FC<HeaderProps> = ({
} }
const breadcrumbItems = [ const breadcrumbItems = [
{ key: 'root', title: <span style={{ cursor: 'pointer' }} onClick={() => onNavigate('/')}>{t('Home')}</span> }, { key: 'root', title: <span style={{ cursor: 'pointer' }} onClick={() => scheduleNavigate('/')}>{t('Home')}</span> },
...path.split('/').filter(Boolean).map((segment, index, arr) => { ...path.split('/').filter(Boolean).map((segment, index, arr) => {
const segmentPath = '/' + arr.slice(0, index + 1).join('/'); const segmentPath = '/' + arr.slice(0, index + 1).join('/');
return { return {
key: segmentPath, key: segmentPath,
title: <span style={{ cursor: 'pointer' }} onClick={() => onNavigate(segmentPath)}>{segment}</span> title: <span style={{ cursor: 'pointer' }} onClick={() => scheduleNavigate(segmentPath)}>{segment}</span>
}; };
}) })
]; ];
@@ -91,7 +112,7 @@ export const Header: React.FC<HeaderProps> = ({
return ( return (
<div <div
style={{ style={{
cursor: 'pointer', cursor: 'text',
padding: `${token.paddingXXS}px ${token.paddingXS}px`, padding: `${token.paddingXXS}px ${token.paddingXS}px`,
borderRadius: token.borderRadius, borderRadius: token.borderRadius,
transition: 'background-color 0.2s', transition: 'background-color 0.2s',
@@ -104,7 +125,7 @@ export const Header: React.FC<HeaderProps> = ({
}} }}
onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = token.colorFillTertiary; }} onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = token.colorFillTertiary; }}
onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = 'transparent'; }} onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = 'transparent'; }}
onClick={handlePathEdit} onDoubleClick={handleBreadcrumbDoubleClick}
> >
<Breadcrumb items={breadcrumbItems} separator="/" style={{ fontSize: token.fontSizeSM }} /> <Breadcrumb items={breadcrumbItems} separator="/" style={{ fontSize: token.fontSizeSM }} />
</div> </div>