feat(KB-057): complete Step 2 — useTerminal hook with history, SSE streaming, and command execution
This commit is contained in:
@@ -63,6 +63,12 @@ export function TaskCard({
|
||||
|
||||
const titleInputRef = useRef<HTMLInputElement>(null);
|
||||
const descTextareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const touchOpenHandledRef = useRef(false);
|
||||
|
||||
const isInteractiveTarget = useCallback((target: EventTarget | null): boolean => {
|
||||
if (!(target instanceof HTMLElement)) return false;
|
||||
return !!target.closest("button, a, input, textarea, select, label, [role='button']");
|
||||
}, []);
|
||||
|
||||
// Reset edit state when task changes
|
||||
useEffect(() => {
|
||||
@@ -134,6 +140,21 @@ export function TaskCard({
|
||||
}
|
||||
}, [task.id, onOpenDetail, addToast, isEditing]);
|
||||
|
||||
const handleCardClick = useCallback((e: React.MouseEvent) => {
|
||||
if (touchOpenHandledRef.current) {
|
||||
touchOpenHandledRef.current = false;
|
||||
return;
|
||||
}
|
||||
if (isInteractiveTarget(e.target)) return;
|
||||
handleClick();
|
||||
}, [handleClick, isInteractiveTarget]);
|
||||
|
||||
const handleTouchEnd = useCallback((e: React.TouchEvent) => {
|
||||
if (isInteractiveTarget(e.target)) return;
|
||||
touchOpenHandledRef.current = true;
|
||||
handleClick();
|
||||
}, [handleClick, isInteractiveTarget]);
|
||||
|
||||
const handleDepClick = useCallback(async (e: React.MouseEvent, depId: string) => {
|
||||
e.stopPropagation(); // Prevent card click
|
||||
try {
|
||||
@@ -308,7 +329,8 @@ export function TaskCard({
|
||||
onDragOver={handleFileDragOver}
|
||||
onDragLeave={handleFileDragLeave}
|
||||
onDrop={handleFileDrop}
|
||||
onClick={handleClick}
|
||||
onClick={handleCardClick}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
>
|
||||
<div className="card-header">
|
||||
|
||||
Reference in New Issue
Block a user