Restore embedded inline comments in Plan/File/Diff views (#456)
* fix(plan-comments): restore embedded inline comment widgets in Plan view Reinstate CodeMirror block-widget comments so plan annotations stay anchored to selected lines and preserve drag/selection behavior without floating overlays. * fix(file-comments): return Files editor comments to embedded widgets Use inline block widgets for file drafts while keeping full-path draft scoping, so similarly named files no longer risk comment collisions. * fix(diff-comments): render inline comments through annotation portals Replace absolute floating positioning with annotation-target portals to keep diff comments attached to their lines across shadow DOM updates. * chore(comments): remove deprecated floating comment hook Drop the unused floating-comment implementation now that plan, file, and diff views all use embedded comment rendering paths. * fix(codemirror): expose gutter width as CSS variable Measure the current CodeMirror gutter and publish --oc-editor-gutter-width on the editor host so inline widgets can size to the visible code area without hardcoded dimensions. * fix(context-panel): publish panel width for embedded widgets Set --oc-context-panel-width on the context panel in both docked and expanded modes so comment widgets can follow the active panel width dynamically. * fix(file-comments): constrain inline input to editor content width Use context-panel and editor-gutter CSS variables to cap comment input width to the visible editor content area, keeping action buttons fully visible in no-wrap mode. * fix(file-comments): constrain inline comment cards to content area Apply the same variable-based width cap to saved comment cards so card actions stay visible when long lines force horizontal scrolling. * fix(diff-comments): stabilize new comment annotation identity Derive new-comment annotation ids from selection side and line range, and reuse that id for portal target lookup and keys to avoid remount glitches.
This commit is contained in:
@@ -66,7 +66,8 @@ import { useUIStore } from '@/stores/useUIStore';
|
||||
import { useFilesViewTabsStore } from '@/stores/useFilesViewTabsStore';
|
||||
import { useGitStatus } from '@/stores/useGitStore';
|
||||
import { useInlineCommentDraftStore } from '@/stores/useInlineCommentDraftStore';
|
||||
import { useFloatingComments } from '@/components/comments/useFloatingComments';
|
||||
import { InlineCommentCard } from '@/components/comments/InlineCommentCard';
|
||||
import { InlineCommentInput } from '@/components/comments/InlineCommentInput';
|
||||
import { opencodeClient } from '@/lib/opencode/client';
|
||||
import { useDirectoryShowHidden } from '@/lib/directoryShowHidden';
|
||||
import { useFilesViewShowGitignored } from '@/lib/filesViewShowGitignored';
|
||||
@@ -1798,23 +1799,65 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
|
||||
return sessionDrafts.filter((d) => d.source === 'file' && d.fileLabel === selectedFile.path);
|
||||
}, [selectedFile, currentSessionId, allDrafts]);
|
||||
|
||||
const floatingComments = useFloatingComments({
|
||||
editorView: editorViewRef.current,
|
||||
wrapperRef: editorWrapperRef,
|
||||
fileDrafts: filesFileDrafts,
|
||||
editingDraftId,
|
||||
commentText: '',
|
||||
lineSelection,
|
||||
isDragging,
|
||||
fileLabel: selectedFile?.path ?? '',
|
||||
onSaveComment: handleSaveComment,
|
||||
onCancelComment: () => setLineSelection(null),
|
||||
onEditDraft: (draft) => {
|
||||
setEditingDraftId(draft.id);
|
||||
setLineSelection(null);
|
||||
},
|
||||
onDeleteDraft: (draft) => removeDraft(draft.sessionKey, draft.id),
|
||||
});
|
||||
const blockWidgets = React.useMemo(() => {
|
||||
const widgets: import('@/components/ui/CodeMirrorEditor').BlockWidgetDef[] = [];
|
||||
|
||||
for (const draft of filesFileDrafts) {
|
||||
if (draft.id === editingDraftId) {
|
||||
widgets.push({
|
||||
afterLine: draft.endLine,
|
||||
id: `edit-${draft.id}`,
|
||||
content: (
|
||||
<InlineCommentInput
|
||||
key={draft.id}
|
||||
initialText={draft.text}
|
||||
fileLabel={selectedFile?.path}
|
||||
lineRange={{ start: draft.startLine, end: draft.endLine }}
|
||||
isEditing={true}
|
||||
onSave={handleSaveComment}
|
||||
onCancel={() => setEditingDraftId(null)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
} else {
|
||||
widgets.push({
|
||||
afterLine: draft.endLine,
|
||||
id: `card-${draft.id}`,
|
||||
content: (
|
||||
<InlineCommentCard
|
||||
key={draft.id}
|
||||
draft={draft}
|
||||
onEdit={() => {
|
||||
setEditingDraftId(draft.id);
|
||||
setLineSelection(null);
|
||||
}}
|
||||
onDelete={() => removeDraft(draft.sessionKey, draft.id)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (lineSelection && !editingDraftId && !isDragging) {
|
||||
widgets.push({
|
||||
afterLine: lineSelection.end,
|
||||
id: 'files-new-comment-input',
|
||||
content: (
|
||||
<InlineCommentInput
|
||||
key="new-comment"
|
||||
initialText=""
|
||||
fileLabel={selectedFile?.path}
|
||||
lineRange={lineSelection}
|
||||
isEditing={false}
|
||||
onSave={handleSaveComment}
|
||||
onCancel={() => setLineSelection(null)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return widgets;
|
||||
}, [filesFileDrafts, editingDraftId, lineSelection, isDragging, selectedFile?.path, handleSaveComment, removeDraft]);
|
||||
|
||||
const fileViewer = (
|
||||
<div
|
||||
@@ -2184,6 +2227,7 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
|
||||
onChange={setDraftContent}
|
||||
extensions={editorExtensions}
|
||||
className="h-full"
|
||||
blockWidgets={blockWidgets}
|
||||
onViewReady={(view) => {
|
||||
editorViewRef.current = view;
|
||||
window.requestAnimationFrame(() => {
|
||||
@@ -2269,7 +2313,6 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{floatingComments}
|
||||
</div>
|
||||
)}
|
||||
</ScrollableOverlay>
|
||||
|
||||
Reference in New Issue
Block a user