From ee830fd9621e553444f485874b04bc595d5a7109 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Wed, 4 Mar 2026 17:08:24 +0000 Subject: [PATCH] feat: add inline editable summary for expanded groups Co-Authored-By: Claude Opus 4.5 --- .../lib/components/graph/GroupOverlay.svelte | 67 +++++++++++++++++-- .../components/graph/groupEditor.svelte.ts | 4 +- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/components/graph/GroupOverlay.svelte b/frontend/src/lib/components/graph/GroupOverlay.svelte index a0ecb3bad6..85d315559d 100644 --- a/frontend/src/lib/components/graph/GroupOverlay.svelte +++ b/frontend/src/lib/components/graph/GroupOverlay.svelte @@ -6,6 +6,7 @@ import GroupActionBar from './GroupActionBar.svelte' import StepCountTab from './StepCountTab.svelte' import type { CollapsedSubflowN } from './graphBuilder.svelte' + import { stopPropagation, preventDefault } from 'svelte/legacy' interface Props { hoveredNodeId: string | null @@ -20,6 +21,35 @@ // Menu open state let menuOpen = $state(false) + // Inline summary editing + let editingGroupId = $state(null) + let summaryInput = $state('') + let summaryInputEl = $state(undefined) + + function startEditingSummary(groupId: string, current: string) { + if (!editMode) return + editingGroupId = groupId + summaryInput = current + requestAnimationFrame(() => { + summaryInputEl?.focus() + summaryInputEl?.select() + }) + } + + function saveSummary(groupId: string) { + editingGroupId = null + const trimmed = summaryInput.trim() + groupEditorContext?.groupEditor.updateSummary(groupId, trimmed) + } + + function handleSummaryKeydown(event: KeyboardEvent, groupId: string) { + if (event.key === 'Enter') { + saveSummary(groupId) + } else if (event.key === 'Escape') { + editingGroupId = null + } + } + // Action bar hover state to prevent flicker let actionBarHovered = $state(false) @@ -179,15 +209,42 @@ short onExpand={() => toggleCollapse(group.id)} /> - {#if group.summary} + {#if editingGroupId === group.id} + {@const textColorClass = + NOTE_COLORS[(group.color as NoteColor) ?? NoteColor.BLUE]?.text ?? ''} + saveSummary(group.id)} + onkeydown={(e) => handleSummaryKeydown(e, group.id)} + onclick={stopPropagation(preventDefault(() => {}))} + onpointerdown={stopPropagation(preventDefault(() => {}))} + spellcheck={false} + /> + {:else} + {@const textColorClass = + NOTE_COLORS[(group.color as NoteColor) ?? NoteColor.BLUE]?.text ?? ''} + + {group.summary} + class="absolute text-3xs font-medium bg-surface-secondary truncate max-w-[150px] text-opacity-60 {textColorClass} {editMode + ? 'cursor-text rounded px-0.5 -mx-0.5 hover:text-opacity-100' + : ''}" + style="top: -18px; left: 76px;" + onclick={editMode + ? stopPropagation( + preventDefault(() => startEditingSummary(group.id, group.summary ?? '')) + ) + : undefined} + onpointerdown={editMode ? stopPropagation(preventDefault(() => {})) : undefined} + >{group.summary || (editMode ? 'Group' : '')} {/if} {#if editMode} -
+