@@ -113,6 +113,7 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit }
const monacoRef = useRef<typeof Monaco | null>(null);
const commentInputRef = useRef<HTMLTextAreaElement>(null);
const modeRef = useRef<ViewMode>(mode);
+ const hoverDecorationsRef = useRef<string[]>([]);
// Keep modeRef in sync with mode state and update editor options
useEffect(() => {
@@ -252,7 +253,7 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit }
minimap: { enabled: false },
scrollBeyondLastLine: true, // Enable scroll past end for mobile floating buttons
wordWrap: "on",
- glyphMargin: false, // No glyph margin - click on lines to comment
+ glyphMargin: !isMobile, // Enable glyph margin for comment indicator on hover
lineDecorationsWidth: isMobile ? 0 : 10,
lineNumbersMinChars: isMobile ? 0 : 3,
quickSuggestions: false,
@@ -346,6 +347,54 @@ function DiffViewer({ cwd, isOpen, onClose, onCommentTextChange, initialCommit }
});
}
+ // Add hover highlighting with comment indicator (comment mode only)
+ let lastHoveredLine = -1;
+ modifiedEditor.onMouseMove((e: Monaco.editor.IEditorMouseEvent) => {
+ // Only show hover effects in comment mode
+ if (modeRef.current !== "comment") {
+ if (hoverDecorationsRef.current.length > 0) {
+ hoverDecorationsRef.current = modifiedEditor.deltaDecorations(
+ hoverDecorationsRef.current,
+ [],
+ );
+ }
+ return;
+ }
+
+ const position = e.target.position;
+ const lineNumber = position?.lineNumber ?? -1;
+
+ if (lineNumber === lastHoveredLine) return;
+ lastHoveredLine = lineNumber;
+
+ if (lineNumber > 0) {
+ hoverDecorationsRef.current = modifiedEditor.deltaDecorations(hoverDecorationsRef.current, [
+ {
+ range: new monaco.Range(lineNumber, 1, lineNumber, 1),
+ options: {
+ isWholeLine: true,
+ className: "diff-viewer-line-hover",
+ glyphMarginClassName: "diff-viewer-comment-glyph",
+ },
+ },
+ ]);
+ } else {
+ hoverDecorationsRef.current = modifiedEditor.deltaDecorations(
+ hoverDecorationsRef.current,
+ [],
+ );
+ }
+ });
+
+ // Clear decorations when mouse leaves editor
+ modifiedEditor.onMouseLeave(() => {
+ lastHoveredLine = -1;
+ hoverDecorationsRef.current = modifiedEditor.deltaDecorations(
+ hoverDecorationsRef.current,
+ [],
+ );
+ });
+
// Add content change listener for auto-save
contentChangeDisposableRef.current?.dispose();
contentChangeDisposableRef.current = modifiedEditor.onDidChangeModelContent(() => {
@@ -3009,6 +3009,38 @@ svg {
width: 100%;
}
+/* Diff viewer line hover highlighting (via decoration API) */
+.diff-viewer-editor .monaco-editor .diff-viewer-line-hover {
+ background-color: rgba(37, 99, 235, 0.08) !important;
+}
+
+.dark .diff-viewer-editor .monaco-editor .diff-viewer-line-hover {
+ background-color: rgba(96, 165, 250, 0.12) !important;
+}
+
+/* Comment indicator glyph in margin for diff viewer */
+.diff-viewer-editor .monaco-editor .diff-viewer-comment-glyph {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'%3E%3C/path%3E%3Cline x1='9' y1='10' x2='15' y2='10'%3E%3C/line%3E%3C/svg%3E");
+ background-size: 14px 14px;
+ background-repeat: no-repeat;
+ background-position: center;
+ opacity: 0.6;
+ cursor: pointer;
+}
+
+.diff-viewer-editor .monaco-editor .diff-viewer-comment-glyph:hover {
+ opacity: 1;
+}
+
+.dark .diff-viewer-editor .monaco-editor .diff-viewer-comment-glyph {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'%3E%3C/path%3E%3Cline x1='9' y1='10' x2='15' y2='10'%3E%3C/line%3E%3C/svg%3E");
+}
+
+/* Make diff viewer Monaco lines clickable with pointer cursor */
+.diff-viewer-editor .monaco-editor .view-lines {
+ cursor: pointer;
+}
+
.diff-viewer-comment-badge {
position: absolute;
bottom: 1rem;