Browse Source

feat: show header controls on node body hover, not just header hover

Add hoveredNodeId to store, set from BaseNode mouse events, read in
FloatingNodeHeader. Controls now appear when hovering any part of
the node, not just the floating header strip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
5cf4c92f52
  1. 3
      src/components/nodes/BaseNode.tsx
  2. 9
      src/components/nodes/FloatingNodeHeader.tsx
  3. 7
      src/store/workflowStore.ts

3
src/components/nodes/BaseNode.tsx

@ -32,6 +32,7 @@ export function BaseNode({
}: BaseNodeProps) {
const currentNodeIds = useWorkflowStore((state) => state.currentNodeIds);
const nodes = useWorkflowStore((state) => state.nodes);
const setHoveredNodeId = useWorkflowStore((state) => state.setHoveredNodeId);
const isCurrentlyExecuting = currentNodeIds.includes(id);
const { getNodes, setNodes } = useReactFlow();
@ -82,6 +83,8 @@ export function BaseNode({
${!fullBleed && selected ? "border-blue-500 ring-2 ring-blue-500/40 shadow-lg shadow-blue-500/25" : ""}
${className}
`}
onMouseEnter={() => setHoveredNodeId(id)}
onMouseLeave={() => setHoveredNodeId(null)}
>
<div className={contentClassName ?? (fullBleed ? "flex-1 min-h-0 relative" : "px-3 pb-4 flex-1 min-h-0 overflow-hidden flex flex-col")}>{children}</div>
</div>

9
src/components/nodes/FloatingNodeHeader.tsx

@ -4,6 +4,7 @@ import { ReactNode, useState, useEffect, useRef, useCallback } from "react";
import { createPortal } from "react-dom";
import { useReactFlow } from "@xyflow/react";
import { NodeType } from "@/types";
import { useWorkflowStore } from "@/store/workflowStore";
export interface CommentNavigationProps {
currentIndex: number;
@ -51,7 +52,9 @@ export function FloatingNodeHeader({
onCommentChange,
commentNavigation,
}: FloatingNodeHeaderProps) {
const [isHovered, setIsHovered] = useState(false);
const [isHeaderHovered, setIsHeaderHovered] = useState(false);
const isBodyHovered = useWorkflowStore((state) => state.hoveredNodeId === id);
const isHovered = isHeaderHovered || isBodyHovered;
const [isEditingTitle, setIsEditingTitle] = useState(false);
const [editTitleValue, setEditTitleValue] = useState(customTitle || "");
const [isEditingComment, setIsEditingComment] = useState(false);
@ -278,8 +281,8 @@ export function FloatingNodeHeader({
width: `${width}px`,
zIndex: selected ? 10000 : 9000,
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
onMouseEnter={() => setIsHeaderHovered(true)}
onMouseLeave={() => setIsHeaderHovered(false)}
onMouseDown={handleHeaderMouseDown}
>
<div className="px-1 py-1 flex items-center justify-between w-full">

7
src/store/workflowStore.ts

@ -243,9 +243,11 @@ interface WorkflowStore {
openModalCount: number;
isModalOpen: boolean;
showQuickstart: boolean;
hoveredNodeId: string | null;
incrementModalCount: () => void;
decrementModalCount: () => void;
setShowQuickstart: (show: boolean) => void;
setHoveredNodeId: (id: string | null) => void;
// Execution
isRunning: boolean;
@ -450,6 +452,7 @@ const workflowStoreImpl: StateCreator<WorkflowStore> = (set, get) => ({
openModalCount: 0,
isModalOpen: false,
showQuickstart: true,
hoveredNodeId: null,
isRunning: false,
currentNodeIds: [], // Changed from currentNodeId for parallel execution
pausedAtNodeId: null,
@ -522,6 +525,10 @@ const workflowStoreImpl: StateCreator<WorkflowStore> = (set, get) => ({
set({ showQuickstart: show });
},
setHoveredNodeId: (id: string | null) => {
set({ hoveredNodeId: id });
},
addNode: (type: NodeType, position: XYPosition, initialData?: Partial<WorkflowNodeData>) => {
const id = `${type}-${++nodeIdCounter}`;

Loading…
Cancel
Save