mirror of https://github.com/langgenius/dify.git
feat: can drag avatar to move the comment input
This commit is contained in:
parent
3ee2508ec8
commit
8497d296b1
|
|
@ -1,5 +1,5 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo, useCallback, useEffect, useState } from 'react'
|
||||
import type { FC, PointerEvent as ReactPointerEvent } from 'react'
|
||||
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Avatar from '@/app/components/base/avatar'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
|
|
@ -10,12 +10,36 @@ type CommentInputProps = {
|
|||
position: { x: number; y: number }
|
||||
onSubmit: (content: string, mentionedUserIds: string[]) => void
|
||||
onCancel: () => void
|
||||
onPositionChange?: (position: {
|
||||
pageX: number
|
||||
pageY: number
|
||||
elementX: number
|
||||
elementY: number
|
||||
}) => void
|
||||
}
|
||||
|
||||
export const CommentInput: FC<CommentInputProps> = memo(({ position, onSubmit, onCancel }) => {
|
||||
export const CommentInput: FC<CommentInputProps> = memo(({ position, onSubmit, onCancel, onPositionChange }) => {
|
||||
const [content, setContent] = useState('')
|
||||
const { t } = useTranslation()
|
||||
const { userProfile } = useAppContext()
|
||||
const dragStateRef = useRef<{
|
||||
pointerId: number | null
|
||||
startPointerX: number
|
||||
startPointerY: number
|
||||
startX: number
|
||||
startY: number
|
||||
active: boolean
|
||||
} & {
|
||||
endHandler?: (event: PointerEvent) => void
|
||||
}>({
|
||||
pointerId: null,
|
||||
startPointerX: 0,
|
||||
startPointerY: 0,
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
active: false,
|
||||
endHandler: undefined,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const handleGlobalKeyDown = (e: KeyboardEvent) => {
|
||||
|
|
@ -37,6 +61,67 @@ export const CommentInput: FC<CommentInputProps> = memo(({ position, onSubmit, o
|
|||
setContent('')
|
||||
}, [onSubmit])
|
||||
|
||||
const handleDragPointerMove = useCallback((event: PointerEvent) => {
|
||||
const state = dragStateRef.current
|
||||
if (!state.active || (state.pointerId !== null && event.pointerId !== state.pointerId))
|
||||
return
|
||||
if (!onPositionChange)
|
||||
return
|
||||
event.preventDefault()
|
||||
const deltaX = event.clientX - state.startPointerX
|
||||
const deltaY = event.clientY - state.startPointerY
|
||||
onPositionChange({
|
||||
pageX: event.clientX,
|
||||
pageY: event.clientY,
|
||||
elementX: state.startX + deltaX,
|
||||
elementY: state.startY + deltaY,
|
||||
})
|
||||
}, [onPositionChange])
|
||||
|
||||
const stopDragging = useCallback((event?: PointerEvent) => {
|
||||
const state = dragStateRef.current
|
||||
if (!state.active)
|
||||
return
|
||||
if (event && state.pointerId !== null && event.pointerId !== state.pointerId)
|
||||
return
|
||||
state.active = false
|
||||
state.pointerId = null
|
||||
window.removeEventListener('pointermove', handleDragPointerMove)
|
||||
if (state.endHandler) {
|
||||
window.removeEventListener('pointerup', state.endHandler)
|
||||
window.removeEventListener('pointercancel', state.endHandler)
|
||||
state.endHandler = undefined
|
||||
}
|
||||
}, [handleDragPointerMove])
|
||||
|
||||
const handleDragPointerDown = useCallback((event: ReactPointerEvent<HTMLDivElement>) => {
|
||||
if (event.button !== 0)
|
||||
return
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
if (!onPositionChange)
|
||||
return
|
||||
const endHandler = (pointerEvent: PointerEvent) => {
|
||||
stopDragging(pointerEvent)
|
||||
}
|
||||
dragStateRef.current = {
|
||||
pointerId: event.pointerId,
|
||||
startPointerX: event.clientX,
|
||||
startPointerY: event.clientY,
|
||||
startX: position.x,
|
||||
startY: position.y,
|
||||
active: true,
|
||||
endHandler,
|
||||
}
|
||||
window.addEventListener('pointermove', handleDragPointerMove, { passive: false })
|
||||
window.addEventListener('pointerup', endHandler)
|
||||
window.addEventListener('pointercancel', endHandler)
|
||||
}, [handleDragPointerMove, onPositionChange, position.x, position.y, stopDragging])
|
||||
|
||||
useEffect(() => () => {
|
||||
stopDragging()
|
||||
}, [stopDragging])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute z-[60] w-96"
|
||||
|
|
@ -47,7 +132,10 @@ export const CommentInput: FC<CommentInputProps> = memo(({ position, onSubmit, o
|
|||
data-comment-input
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="relative shrink-0">
|
||||
<div
|
||||
className="relative shrink-0 cursor-move"
|
||||
onPointerDown={handleDragPointerDown}
|
||||
>
|
||||
<div className="relative h-8 w-8 overflow-hidden rounded-br-full rounded-tl-full rounded-tr-full bg-primary-500">
|
||||
<div className="absolute inset-[2px] overflow-hidden rounded-br-full rounded-tl-full rounded-tr-full bg-white">
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ import {
|
|||
useStore,
|
||||
useWorkflowStore,
|
||||
} from './store'
|
||||
import type { WorkflowSliceShape } from './store/workflow/workflow-slice'
|
||||
import {
|
||||
CUSTOM_EDGE,
|
||||
CUSTOM_NODE,
|
||||
|
|
@ -210,6 +211,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
const showUserComments = useStore(s => s.showUserComments)
|
||||
const showUserCursors = useStore(s => s.showUserCursors)
|
||||
const isCommentPreviewHovering = useStore(s => s.isCommentPreviewHovering)
|
||||
const setPendingCommentState = useStore(s => s.setPendingComment)
|
||||
const isCommentInputActive = Boolean(pendingComment)
|
||||
const { t } = useTranslation()
|
||||
|
||||
|
|
@ -244,6 +246,10 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
}
|
||||
}, [])
|
||||
|
||||
const handlePendingCommentPositionChange = useCallback((position: NonNullable<WorkflowSliceShape['pendingComment']>) => {
|
||||
setPendingCommentState(position)
|
||||
}, [setPendingCommentState])
|
||||
|
||||
const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft()
|
||||
const handleSyncWorkflowDraftWhenPageClose = useCallback(() => {
|
||||
if (document.visibilityState === 'hidden')
|
||||
|
|
@ -483,6 +489,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
}}
|
||||
onSubmit={handleCommentSubmit}
|
||||
onCancel={handleCommentCancel}
|
||||
onPositionChange={handlePendingCommentPositionChange}
|
||||
/>
|
||||
)}
|
||||
{comments.map((comment, index) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue