refactor: unified shortcut keys display using component (#31713)

This commit is contained in:
CrabSAMA 2026-01-29 17:57:46 +08:00 committed by GitHub
parent 62f46fc55c
commit 7d1ad7e03a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 41 additions and 106 deletions

View File

@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
import { cn } from '@/utils/classnames'
import Button from '../base/button'
import Tooltip from '../base/tooltip'
import { getKeyboardKeyNameBySystem } from '../workflow/utils'
import ShortcutsName from '../workflow/shortcuts-name'
type TooltipContentProps = {
expand: boolean
@ -20,18 +20,7 @@ const TooltipContent = ({
return (
<div className="flex items-center gap-x-1">
<span className="system-xs-medium px-0.5 text-text-secondary">{expand ? t('sidebar.collapseSidebar', { ns: 'layout' }) : t('sidebar.expandSidebar', { ns: 'layout' })}</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>
<ShortcutsName keys={TOGGLE_SHORTCUT} textColor="secondary" />
</div>
)
}

View File

@ -49,7 +49,8 @@ import Divider from '../../base/divider'
import Loading from '../../base/loading'
import Toast from '../../base/toast'
import Tooltip from '../../base/tooltip'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '../../workflow/utils'
import ShortcutsName from '../../workflow/shortcuts-name'
import { getKeyboardKeyCodeBySystem } from '../../workflow/utils'
import AccessControl from '../app-access-control'
import PublishWithMultipleModel from './publish-with-multiple-model'
import SuggestedAction from './suggested-action'
@ -345,13 +346,7 @@ const AppPublisher = ({
: (
<div className="flex gap-1">
<span>{t('common.publishUpdate', { ns: 'workflow' })}</span>
<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">
{getKeyboardKeyNameBySystem(key)}
</span>
))}
</div>
<ShortcutsName keys={PUBLISH_SHORTCUT} bgColor="white" />
</div>
)
}

View File

@ -1,7 +1,7 @@
'use client'
import type { AppIconSelection } from '../../base/app-icon-picker'
import { RiArrowRightLine, RiArrowRightSLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react'
import { RiArrowRightLine, RiArrowRightSLine, RiExchange2Fill } from '@remixicon/react'
import { useDebounceFn, useKeyPress } from 'ahooks'
import Image from 'next/image'
@ -29,6 +29,7 @@ import { getRedirection } from '@/utils/app-redirection'
import { cn } from '@/utils/classnames'
import { basePath } from '@/utils/var'
import AppIconPicker from '../../base/app-icon-picker'
import ShortcutsName from '../../workflow/shortcuts-name'
type CreateAppProps = {
onSuccess: () => void
@ -269,10 +270,7 @@ function CreateApp({ onClose, onSuccess, onCreateFromTemplate, defaultAppMode }:
<Button onClick={onClose}>{t('newApp.Cancel', { ns: 'app' })}</Button>
<Button disabled={isAppsFull || !name} className="gap-1" variant="primary" onClick={handleCreateApp}>
<span>{t('newApp.Create', { ns: 'app' })}</span>
<div className="flex gap-0.5">
<RiCommandLine size={14} className="system-kbd rounded-sm bg-components-kbd-bg-white p-0.5" />
<RiCornerDownLeftLine size={14} className="system-kbd rounded-sm bg-components-kbd-bg-white p-0.5" />
</div>
<ShortcutsName keys={['ctrl', '↵']} bgColor="white" />
</Button>
</div>
</div>

View File

@ -1,7 +1,7 @@
'use client'
import type { MouseEventHandler } from 'react'
import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react'
import { RiCloseLine } from '@remixicon/react'
import { useDebounceFn, useKeyPress } from 'ahooks'
import { noop } from 'es-toolkit/function'
import { useRouter } from 'next/navigation'
@ -28,6 +28,7 @@ import {
} from '@/service/apps'
import { getRedirection } from '@/utils/app-redirection'
import { cn } from '@/utils/classnames'
import ShortcutsName from '../../workflow/shortcuts-name'
import Uploader from './uploader'
type CreateFromDSLModalProps = {
@ -298,10 +299,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose, activeTab = CreateFromDS
className="gap-1"
>
<span>{t('newApp.Create', { ns: 'app' })}</span>
<div className="flex gap-0.5">
<RiCommandLine size={14} className="system-kbd rounded-sm bg-components-kbd-bg-white p-0.5" />
<RiCornerDownLeftLine size={14} className="system-kbd rounded-sm bg-components-kbd-bg-white p-0.5" />
</div>
<ShortcutsName keys={['ctrl', '↵']} bgColor="white" />
</Button>
</div>
</Modal>

View File

@ -4,7 +4,8 @@ import * as React from 'react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { getKeyboardKeyCodeBySystem } from '@/app/components/workflow/utils'
import { ChunkingMode } from '@/models/datasets'
import { useDocumentContext } from '../../context'
@ -54,7 +55,7 @@ const ActionButtons: FC<IActionButtonsProps> = ({
>
<div className="flex items-center gap-x-1">
<span className="system-sm-medium text-components-button-secondary-text">{t('operation.cancel', { ns: 'common' })}</span>
<span className="system-kbd rounded-[4px] bg-components-kbd-bg-gray px-[1px] text-text-tertiary">ESC</span>
<ShortcutsName keys={['ESC']} textColor="secondary" />
</div>
</Button>
{(isParentChildParagraphMode && actionType === 'edit' && !isChildChunk && showRegenerationButton)
@ -76,10 +77,7 @@ const ActionButtons: FC<IActionButtonsProps> = ({
>
<div className="flex items-center gap-x-1">
<span className="text-components-button-primary-text">{t('operation.save', { ns: 'common' })}</span>
<div className="flex items-center gap-x-0.5">
<span className="system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white capitalize text-text-primary-on-surface">{getKeyboardKeyNameBySystem('ctrl')}</span>
<span className="system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white text-text-primary-on-surface">S</span>
</div>
<ShortcutsName keys={['ctrl', 'S']} bgColor="white" />
</div>
</Button>
</div>

View File

@ -1,6 +1,6 @@
'use client'
import type { AppIconType } from '@/types/app'
import { RiCloseLine, RiCommandLine, RiCornerDownLeftLine } from '@remixicon/react'
import { RiCloseLine } from '@remixicon/react'
import { useDebounceFn, useKeyPress } from 'ahooks'
import { noop } from 'es-toolkit/function'
import * as React from 'react'
@ -17,6 +17,7 @@ import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import { useProviderContext } from '@/context/provider-context'
import { AppModeEnum } from '@/types/app'
import AppIconPicker from '../../base/app-icon-picker'
import ShortcutsName from '../../workflow/shortcuts-name'
export type CreateAppModalProps = {
show: boolean
@ -198,10 +199,7 @@ const CreateAppModal = ({
onClick={handleSubmit}
>
<span>{!isEditModal ? t('operation.create', { ns: 'common' }) : t('operation.save', { ns: 'common' })}</span>
<div className="flex gap-0.5">
<RiCommandLine size={14} className="system-kbd rounded-sm bg-components-kbd-bg-white p-0.5" />
<RiCornerDownLeftLine size={14} className="system-kbd rounded-sm bg-components-kbd-bg-white p-0.5" />
</div>
<ShortcutsName keys={['ctrl', '↵']} bgColor="white" />
</Button>
<Button className="w-24" onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</Button>
</div>

View File

@ -12,7 +12,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import Modal from '@/app/components/base/modal'
import { getKeyboardKeyCodeBySystem, isEventTargetInputArea, isMac } from '@/app/components/workflow/utils/common'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { getKeyboardKeyCodeBySystem, isEventTargetInputArea } from '@/app/components/workflow/utils/common'
import { selectWorkflowNode } from '@/app/components/workflow/utils/node-navigation'
import { useGetLanguage } from '@/context/i18n'
import InstallFromMarketplace from '../plugins/install-plugin/install-from-marketplace'
@ -356,14 +357,7 @@ const GotoAnything: FC<Props> = ({
</div>
)}
</div>
<div className="text-xs text-text-quaternary">
<span className="system-kbd rounded bg-gray-200 px-1 py-[2px] font-mono text-gray-700 dark:bg-gray-800 dark:text-gray-100">
{isMac() ? '⌘' : 'Ctrl'}
</span>
<span className="system-kbd ml-1 rounded bg-gray-200 px-1 py-[2px] font-mono text-gray-700 dark:bg-gray-800 dark:text-gray-100">
K
</span>
</div>
<ShortcutsName keys={['ctrl', 'K']} textColor="secondary" />
</div>
<Command.List className="h-[240px] overflow-y-auto">

View File

@ -28,11 +28,12 @@ import { useToastContext } from '@/app/components/base/toast'
import {
useChecklistBeforePublish,
} from '@/app/components/workflow/hooks'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import {
useStore,
useWorkflowStore,
} from '@/app/components/workflow/store'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
import { getKeyboardKeyCodeBySystem } from '@/app/components/workflow/utils'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import { useDocLink } from '@/context/i18n'
import { useModalContextSelector } from '@/context/modal-context'
@ -261,13 +262,7 @@ const Popup = () => {
: (
<div className="flex gap-1">
<span>{t('common.publishUpdate', { ns: 'workflow' })}</span>
<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">
{getKeyboardKeyNameBySystem(key)}
</span>
))}
</div>
<ShortcutsName keys={PUBLISH_SHORTCUT} bgColor="white" />
</div>
)
}

View File

@ -4,9 +4,9 @@ import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { StopCircle } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import { useWorkflowRun, useWorkflowStartRun } from '@/app/components/workflow/hooks'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
import { getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
import { EVENT_WORKFLOW_STOP } from '@/app/components/workflow/variable-inspect/types'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import { cn } from '@/utils/classnames'
@ -78,14 +78,7 @@ const RunMode = ({
)}
{
!isDisabled && (
<div className="system-kbd flex items-center gap-x-0.5 text-text-tertiary">
<div className="flex size-4 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray">
{getKeyboardKeyNameBySystem('alt')}
</div>
<div className="flex size-4 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray">
R
</div>
</div>
<ShortcutsName keys={['alt', 'R']} textColor="secondary" />
)
}
</button>

View File

@ -7,6 +7,7 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import Modal from '@/app/components/base/modal'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { BlockEnum } from '@/app/components/workflow/types'
import StartNodeSelectionPanel from './start-node-selection-panel'
@ -75,9 +76,7 @@ const WorkflowOnboardingModal: FC<WorkflowOnboardingModalProps> = ({
{isShow && (
<div className="body-xs-regular pointer-events-none fixed left-1/2 top-1/2 z-[70] flex -translate-x-1/2 translate-y-[165px] items-center gap-1 text-text-quaternary">
<span>{t('onboarding.escTip.press', { ns: 'workflow' })}</span>
<kbd className="system-kbd inline-flex h-4 min-w-4 items-center justify-center rounded bg-components-kbd-bg-gray px-1 text-text-tertiary">
{t('onboarding.escTip.key', { ns: 'workflow' })}
</kbd>
<ShortcutsName keys={[t('onboarding.escTip.key', { ns: 'workflow' })]} textColor="secondary" />
<span>{t('onboarding.escTip.toDismiss', { ns: 'workflow' })}</span>
</div>
)}

View File

@ -7,9 +7,9 @@ import { trackEvent } from '@/app/components/base/amplitude'
import { StopCircle } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
import { useToastContext } from '@/app/components/base/toast'
import { useWorkflowRun, useWorkflowRunValidation, useWorkflowStartRun } from '@/app/components/workflow/hooks'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { useStore } from '@/app/components/workflow/store'
import { WorkflowRunningStatus } from '@/app/components/workflow/types'
import { getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
import { EVENT_WORKFLOW_STOP } from '@/app/components/workflow/variable-inspect/types'
import { useEventEmitterContextContext } from '@/context/event-emitter'
import { cn } from '@/utils/classnames'
@ -143,14 +143,7 @@ const RunMode = ({
>
<RiPlayLargeLine className="mr-1 size-4" />
{text ?? t('common.run', { ns: 'workflow' })}
<div className="system-kbd flex items-center gap-x-0.5 text-text-tertiary">
<div className="flex size-4 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray">
{getKeyboardKeyNameBySystem('alt')}
</div>
<div className="flex size-4 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray">
R
</div>
</div>
<ShortcutsName keys={['alt', 'R']} textColor="secondary" />
</div>
</TestRunMenu>
)

View File

@ -8,7 +8,8 @@ import useTheme from '@/hooks/use-theme'
import { cn } from '@/utils/classnames'
import Button from '../../base/button'
import Tooltip from '../../base/tooltip'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '../utils'
import ShortcutsName from '../shortcuts-name'
import { getKeyboardKeyCodeBySystem } from '../utils'
type VersionHistoryButtonProps = {
onClick: () => Promise<unknown> | unknown
@ -23,16 +24,7 @@ const PopupContent = React.memo(() => {
<div className="system-xs-medium px-0.5 text-text-secondary">
{t('common.versionHistory', { ns: 'workflow' })}
</div>
<div className="flex items-center gap-x-0.5">
{VERSION_HISTORY_SHORTCUT.map(key => (
<span
key={key}
className="system-kbd rounded-[4px] bg-components-kbd-bg-white px-[1px] text-text-tertiary"
>
{getKeyboardKeyNameBySystem(key)}
</span>
))}
</div>
<ShortcutsName keys={VERSION_HISTORY_SHORTCUT} bgColor="gray" textColor="secondary" />
</div>
)
})

View File

@ -3,7 +3,8 @@ import { useKeyPress } from 'ahooks'
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import Button from '@/app/components/base/button'
import { getKeyboardKeyCodeBySystem, getKeyboardKeyNameBySystem } from '@/app/components/workflow/utils'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import { getKeyboardKeyCodeBySystem } from '@/app/components/workflow/utils'
type AdvancedActionsProps = {
isConfirmDisabled: boolean
@ -11,15 +12,6 @@ type AdvancedActionsProps = {
onConfirm: () => void
}
const Key = (props: { keyName: string }) => {
const { keyName } = props
return (
<kbd className="system-kbd flex h-4 min-w-4 items-center justify-center rounded-[4px] bg-components-kbd-bg-white px-px text-text-primary-on-surface">
{keyName}
</kbd>
)
}
const AdvancedActions: FC<AdvancedActionsProps> = ({
isConfirmDisabled,
onCancel,
@ -48,10 +40,7 @@ const AdvancedActions: FC<AdvancedActionsProps> = ({
onClick={onConfirm}
>
<span>{t('operation.confirm', { ns: 'common' })}</span>
<div className="flex items-center gap-x-0.5">
<Key keyName={getKeyboardKeyNameBySystem('ctrl')} />
<Key keyName="⏎" />
</div>
<ShortcutsName keys={['ctrl', '⏎']} bgColor="white" />
</Button>
</div>
)

View File

@ -6,11 +6,13 @@ type ShortcutsNameProps = {
keys: string[]
className?: string
textColor?: 'default' | 'secondary'
bgColor?: 'gray' | 'white'
}
const ShortcutsName = ({
keys,
className,
textColor = 'default',
bgColor = 'gray',
}: ShortcutsNameProps) => {
return (
<div className={cn(
@ -23,7 +25,9 @@ const ShortcutsName = ({
<div
key={key}
className={cn(
'system-kbd flex h-4 min-w-4 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray capitalize',
'system-kbd flex h-4 min-w-4 items-center justify-center rounded-[4px] px-1 capitalize',
bgColor === 'gray' && 'bg-components-kbd-bg-gray',
bgColor === 'white' && 'bg-components-kbd-bg-white text-text-primary-on-surface',
textColor === 'secondary' && 'text-text-tertiary',
)}
>