feat: Implement sidebar toggle functionality with keyboard shortcuts and improve translations

feat/rag-2
twwu 7 months ago
parent b3431ab0c4
commit 1c85dada53

@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { usePathname } from 'next/navigation'
import { useShallow } from 'zustand/react/shallow'
import { RiLayoutLeft2Line, RiLayoutRight2Line } from '@remixicon/react'
import NavLink from './navLink'
import type { NavIcon } from './navLink'
import AppInfo from './app-info'
@ -11,6 +10,10 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useStore as useAppStore } from '@/app/components/app/store'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import cn from '@/utils/classnames'
import Divider from '../base/divider'
import { useHover, useKeyPress } from 'ahooks'
import ToggleButton from './toggle-button'
import { getKeyboardKeyCodeBySystem } from '../workflow/utils'
export type IAppDetailNavProps = {
iconType?: 'app' | 'dataset' | 'notion'
@ -33,15 +36,18 @@ const AppDetailNav = ({
appSidebarExpand: state.appSidebarExpand,
setAppSidebarExpand: state.setAppSidebarExpand,
})))
const sidebarRef = React.useRef<HTMLDivElement>(null)
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
const expand = appSidebarExpand === 'expand'
const handleToggle = (state: string) => {
setAppSidebarExpand(state === 'expand' ? 'collapse' : 'expand')
}
const handleToggle = useCallback(() => {
setAppSidebarExpand(appSidebarExpand === 'expand' ? 'collapse' : 'expand')
}, [appSidebarExpand, setAppSidebarExpand])
const isHoveringSidebar = useHover(sidebarRef)
// // Check if the current path is a workflow canvas & fullscreen
// Check if the current path is a workflow canvas & fullscreen
const pathname = usePathname()
const inWorkflowCanvas = pathname.endsWith('/workflow')
const workflowCanvasMaximize = localStorage.getItem('workflow-canvas-maximize') === 'true'
@ -60,16 +66,22 @@ const AppDetailNav = ({
}
}, [appSidebarExpand, setAppSidebarExpand])
useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.b`, (e) => {
e.preventDefault()
handleToggle()
}, { exactMatch: true, useCapture: true })
if (inWorkflowCanvas && hideHeader) {
return (
return (
<div className='flex w-0 shrink-0'>
<AppSidebarDropdown navigation={navigation} />
</div>
)
}
}
return (
<div
ref={sidebarRef}
className={`
flex shrink-0 flex-col border-r border-divider-burn bg-background-default-subtle transition-all
${expand ? 'w-[216px]' : 'w-14'}
@ -91,14 +103,30 @@ const AppDetailNav = ({
/>
)}
</div>
<div className='px-4'>
<div className={cn('mx-auto mt-1 h-[1px] bg-divider-subtle', !expand && 'w-6')} />
<div className='relative px-4 py-2'>
<Divider
type='horizontal'
bgStyle={expand ? 'gradient' : 'solid'}
className={cn(
'my-0 h-px',
expand
? 'bg-gradient-to-r from-divider-subtle to-background-gradient-mask-transparent'
: 'bg-divider-subtle',
)}
/>
{!isMobile && isHoveringSidebar && (
<ToggleButton
className='absolute -right-3 top-[-3.5px] z-20'
expand={expand}
handleToggle={handleToggle}
/>
)}
</div>
<nav
className={`
grow space-y-1
${expand ? 'p-4' : 'px-2.5 py-4'}
`}
className={cn(
'flex grow flex-col gap-y-0.5',
expand ? 'px-3 py-2' : 'p-3',
)}
>
{navigation.map((item, index) => {
return (
@ -113,27 +141,6 @@ const AppDetailNav = ({
)
})}
</nav>
{
!isMobile && (
<div
className={`
shrink-0 py-3
${expand ? 'px-6' : 'px-4'}
`}
>
<div
className='flex h-6 w-6 cursor-pointer items-center justify-center'
onClick={() => handleToggle(appSidebarExpand)}
>
{
expand
? <RiLayoutRight2Line className='h-5 w-5 text-components-menu-item-text' />
: <RiLayoutLeft2Line className='h-5 w-5 text-components-menu-item-text' />
}
</div>
</div>
)
}
</div>
)
}

@ -48,18 +48,18 @@ export default function NavLink({
type='button'
disabled
className={classNames(
'opacity-30 text-components-menu-item-text hover:bg-state-base-hover group flex items-center h-9 rounded-md py-2 system-sm-medium cursor-not-allowed',
mode === 'expand' ? 'px-3' : 'px-2.5',
'system-sm-medium flex h-8 cursor-not-allowed items-center rounded-lg text-components-menu-item-text opacity-30 hover:bg-state-base-hover',
mode === 'expand' ? 'pl-3 pr-1' : 'px-1.5',
)}
title={mode === 'collapse' ? name : ''}
aria-disabled
>
<NavIcon
className={classNames(
'h-4 w-4 flex-shrink-0',
'h-4 w-4 shrink-0',
mode === 'expand' ? 'mr-2' : 'mr-0',
)}
aria-hidden="true"
aria-hidden='true'
/>
{mode === 'expand' && name}
</button>
@ -71,18 +71,20 @@ export default function NavLink({
key={name}
href={href}
className={classNames(
isActive ? 'bg-state-accent-active text-text-accent font-semibold' : 'text-components-menu-item-text hover:bg-state-base-hover hover:text-components-menu-item-text-hover',
'group flex items-center h-9 rounded-md py-2 system-sm-medium',
mode === 'expand' ? 'px-3' : 'px-2.5',
isActive
? 'system-sm-semibold border-b-[0.25px] border-l-[0.75px] border-r-[0.25px] border-t-[0.75px] border-effects-highlight-lightmode-off bg-state-accent-active text-text-accent-light-mode-only'
: 'system-sm-medium text-components-menu-item-text hover:bg-state-base-hover hover:text-components-menu-item-text-hover',
'flex h-8 items-center rounded-lg',
mode === 'expand' ? 'pl-3 pr-1' : 'px-1.5',
)}
title={mode === 'collapse' ? name : ''}
>
<NavIcon
className={classNames(
'h-4 w-4 flex-shrink-0',
'h-4 w-4 shrink-0',
mode === 'expand' ? 'mr-2' : 'mr-0',
)}
aria-hidden="true"
aria-hidden='true'
/>
{mode === 'expand' && name}
</Link>

@ -0,0 +1,71 @@
import React from 'react'
import Button from '../base/button'
import { RiArrowLeftSLine, RiArrowRightSLine } from '@remixicon/react'
import cn from '@/utils/classnames'
import Tooltip from '../base/tooltip'
import { useTranslation } from 'react-i18next'
import { getKeyboardKeyNameBySystem } from '../workflow/utils'
type TooltipContentProps = {
expand: boolean
}
const TOGGLE_SHORTCUT = ['ctrl', 'B']
const TooltipContent = ({
expand,
}: TooltipContentProps) => {
const { t } = useTranslation()
return (
<div className='flex items-center gap-x-1'>
<span className='system-xs-medium px-0.5 text-text-secondary'>{expand ? t('layout.sidebar.collapseSidebar') : t('layout.sidebar.expandSidebar')}</span>
<div className='flex items-center gap-x-0.5'>
{
TOGGLE_SHORTCUT.map(key => (
<span
key={key}
className='system-kbd inline-flex items-center justify-center rounded-[4px] bg-components-kbd-bg-gray px-1 text-text-tertiary'
>
{getKeyboardKeyNameBySystem(key)}
</span>
))
}
</div>
</div>
)
}
type ToggleButtonProps = {
expand: boolean
handleToggle: () => void
className?: string
}
const ToggleButton = ({
expand,
handleToggle,
className,
}: ToggleButtonProps) => {
return (
<Tooltip
popupContent={<TooltipContent expand={expand} />}
popupClassName='p-1.5 rounded-lg'
position='right'
>
<Button
size='small'
onClick={handleToggle}
className={cn('rounded-full px-1', className)}
>
{
expand
? <RiArrowLeftSLine className='size-4' />
: <RiArrowRightSLine className='size-4' />
}
</Button>
</Tooltip>
)
}
export default React.memo(ToggleButton)

@ -19,7 +19,7 @@ import {
RiVerifiedBadgeLine,
} from '@remixicon/react'
import { useKeyPress } from 'ahooks'
import { getKeyboardKeyCodeBySystem } from '../../workflow/utils'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '../../workflow/utils'
import Toast from '../../base/toast'
import type { ModelAndParameter } from '../configuration/debug/types'
import Divider from '../../base/divider'
@ -67,7 +67,7 @@ export type AppPublisherProps = {
onRefreshData?: () => void
}
const PUBLISH_SHORTCUT = ['', '⇧', 'P']
const PUBLISH_SHORTCUT = ['ctrl', '⇧', 'P']
const AppPublisher = ({
disabled = false,
@ -255,7 +255,7 @@ const AppPublisher = ({
<div className='flex gap-0.5'>
{PUBLISH_SHORTCUT.map(key => (
<span key={key} className='system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white text-text-primary-on-surface'>
{key}
{getKeyboardKeyNameBySystem(key)}
</span>
))}
</div>

@ -24,7 +24,7 @@ import {
useFormatTimeFromNow,
} from '@/app/components/workflow/hooks'
import Divider from '@/app/components/base/divider'
import { getKeyboardKeyCodeBySystem } from '@/app/components/workflow/utils'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
import { usePublishWorkflow } from '@/service/use-workflow'
import type { PublishWorkflowParams } from '@/types/workflow'
import { useToastContext } from '@/app/components/base/toast'
@ -39,7 +39,7 @@ import Confirm from '@/app/components/base/confirm'
import PublishAsKnowledgePipelineModal from '../../publish-as-knowledge-pipeline-modal'
import type { IconInfo } from '@/models/datasets'
const PUBLISH_SHORTCUT = ['', '⇧', 'P']
const PUBLISH_SHORTCUT = ['ctrl', '⇧', 'P']
const Popup = () => {
const { t } = useTranslation()
@ -191,7 +191,7 @@ const Popup = () => {
<div className='flex gap-0.5'>
{PUBLISH_SHORTCUT.map(key => (
<span key={key} className='system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white text-text-primary-on-surface'>
{key}
{getKeyboardKeyNameBySystem(key)}
</span>
))}
</div>

@ -4,13 +4,13 @@ import { useTranslation } from 'react-i18next'
import { useKeyPress } from 'ahooks'
import Button from '../../base/button'
import Tooltip from '../../base/tooltip'
import { getKeyboardKeyCodeBySystem } from '../utils'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '../utils'
type VersionHistoryButtonProps = {
onClick: () => Promise<unknown> | unknown
}
const VERSION_HISTORY_SHORTCUT = ['', '⇧', 'H']
const VERSION_HISTORY_SHORTCUT = ['ctrl', '⇧', 'H']
const PopupContent = React.memo(() => {
const { t } = useTranslation()
@ -25,7 +25,7 @@ const PopupContent = React.memo(() => {
key={key}
className='system-kbd rounded-[4px] bg-components-kbd-bg-white px-[1px] text-text-tertiary'
>
{key}
{getKeyboardKeyNameBySystem(key)}
</span>
))}
</div>
@ -45,8 +45,7 @@ const VersionHistoryButton: FC<VersionHistoryButtonProps> = ({
useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.h`, (e) => {
e.preventDefault()
handleViewVersionHistory()
},
{ exactMatch: true, useCapture: true })
}, { exactMatch: true, useCapture: true })
return <Tooltip
popupContent={<PopupContent />}

@ -1,4 +1,8 @@
const translation = {
sidebar: {
expandSidebar: 'Expand Sidebar',
collapseSidebar: 'Collapse Sidebar',
},
}
export default translation

@ -1,4 +1,8 @@
const translation = {
sidebar: {
expandSidebar: '展开侧边栏',
collapseSidebar: '收起侧边栏',
},
}
export default translation

Loading…
Cancel
Save