@@ -3,6 +3,31 @@ import SwiftUI
33import NoturcodeCore
44import UniformTypeIdentifiers
55
6+ private final class PointingHandCursorView : NSView {
7+ override func resetCursorRects( ) {
8+ super. resetCursorRects ( )
9+ addCursorRect ( bounds, cursor: . pointingHand)
10+ }
11+
12+ override func hitTest( _ point: NSPoint ) -> NSView ? { nil }
13+ }
14+
15+ private struct PointingHandCursorRegion : NSViewRepresentable {
16+ func makeNSView( context: Context ) -> PointingHandCursorView {
17+ PointingHandCursorView ( frame: . zero)
18+ }
19+
20+ func updateNSView( _ nsView: PointingHandCursorView , context: Context ) {
21+ nsView. window? . invalidateCursorRects ( for: nsView)
22+ }
23+ }
24+
25+ extension View {
26+ func clickableCursor( ) -> some View {
27+ background ( PointingHandCursorRegion ( ) )
28+ }
29+ }
30+
631struct NoturcodeBrandMark : View {
732 let size : CGFloat
833
@@ -614,6 +639,7 @@ private struct SessionRow: View {
614639 . contentShape ( Circle ( ) )
615640 }
616641 . buttonStyle ( . plain)
642+ . clickableCursor ( )
617643 . help ( " Disconnect from Noturcode — keeps the terminal and agent running " )
618644 . accessibilityLabel ( " Disconnect from Noturcode " )
619645 . accessibilityHint ( " Removes this card without stopping the terminal session " )
@@ -631,6 +657,7 @@ private struct SessionRow: View {
631657 . contentShape ( Capsule ( ) )
632658 }
633659 . buttonStyle ( . plain)
660+ . clickableCursor ( )
634661 . accessibilityIdentifier ( " view-terminal- \( session. id) " )
635662 }
636663 . font ( . system( size: 10.5 , weight: . regular) )
@@ -662,6 +689,7 @@ private struct SessionRow: View {
662689 . onTapGesture ( perform: onSelect)
663690 . frame ( maxWidth: . infinity)
664691 . onHover ( perform: onHover)
692+ . clickableCursor ( )
665693 . animation ( reduceMotion ? nil : . snappy( duration: 0.18 , extraBounce: 0 ) , value: isHovered)
666694 . animation ( reduceMotion ? nil : . easeOut( duration: 0.08 ) , value: isPressed)
667695 . animation ( reduceMotion ? nil : . easeOut( duration: 0.16 ) , value: isUnreadFinished)
@@ -695,6 +723,7 @@ private struct ConversationSidebarToggle: View {
695723 }
696724 }
697725 . buttonStyle ( ConversationControlButtonStyle ( reduceMotion: reduceMotion) )
726+ . clickableCursor ( )
698727 . onHover { hovering in
699728 withAnimation ( reduceMotion ? nil : . easeOut( duration: 0.10 ) ) {
700729 isHovered = hovering
@@ -879,6 +908,7 @@ struct TerminalViewportContent: View {
879908 . contentShape ( Rectangle ( ) )
880909 }
881910 . buttonStyle ( . plain)
911+ . clickableCursor ( )
882912 . help ( isSidebarVisible ? " Hide sidebar " : " Show sidebar " )
883913 . accessibilityLabel ( isSidebarVisible ? " Hide sidebar " : " Show sidebar " )
884914 . accessibilityIdentifier ( " toggle-chat-sidebar " )
@@ -895,6 +925,7 @@ struct TerminalViewportContent: View {
895925 . background ( . white. opacity ( 0.055 ) , in: Capsule ( ) )
896926 }
897927 . buttonStyle ( . plain)
928+ . clickableCursor ( )
898929 . help ( " Compact this \( session. key. source. displayName) session " )
899930 . accessibilityIdentifier ( " compact-session " )
900931 }
@@ -907,6 +938,7 @@ struct TerminalViewportContent: View {
907938 . background ( . white. opacity ( 0.08 ) , in: Circle ( ) )
908939 }
909940 . buttonStyle ( . plain)
941+ . clickableCursor ( )
910942 . accessibilityLabel ( " Close session chat " )
911943 . accessibilityIdentifier ( " close-terminal-preview " )
912944 }
@@ -1069,6 +1101,7 @@ struct TerminalViewportContent: View {
10691101 . background ( . regularMaterial, in: Circle ( ) )
10701102 }
10711103 . buttonStyle ( . plain)
1104+ . clickableCursor ( )
10721105 . padding ( 8 )
10731106 . help ( " Jump to latest message " )
10741107 . accessibilityIdentifier ( " chat-jump-to-latest " )
@@ -1125,6 +1158,7 @@ struct TerminalViewportContent: View {
11251158 . background ( . white. opacity ( 0.035 ) , in: RoundedRectangle ( cornerRadius: 9 , style: . continuous) )
11261159 }
11271160 . buttonStyle ( . plain)
1161+ . clickableCursor ( )
11281162 . accessibilityIdentifier ( " return-to-session-chat " )
11291163 }
11301164 }
@@ -1236,6 +1270,7 @@ struct TerminalViewportContent: View {
12361270 . contentShape ( Rectangle ( ) )
12371271 }
12381272 . buttonStyle ( . plain)
1273+ . clickableCursor ( )
12391274 . accessibilityLabel ( " Show workflow sidebar " )
12401275 . accessibilityIdentifier ( " show-chat-sidebar-rail " )
12411276 . transition ( . move( edge: . trailing) . combined ( with: . opacity) )
@@ -1366,6 +1401,7 @@ struct TerminalViewportContent: View {
13661401 . contentShape ( Rectangle ( ) )
13671402 }
13681403 . buttonStyle ( . plain)
1404+ . clickableCursor ( )
13691405 . help ( " Hide sidebar " )
13701406 . accessibilityLabel ( " Close workflow sidebar " )
13711407 . accessibilityIdentifier ( " close-chat-sidebar " )
@@ -1436,6 +1472,7 @@ struct TerminalViewportContent: View {
14361472 . background ( . white. opacity ( selectedWorkflowNodeID == node. id ? 0.09 : 0.035 ) , in: RoundedRectangle ( cornerRadius: 8 , style: . continuous) )
14371473 }
14381474 . buttonStyle ( . plain)
1475+ . clickableCursor ( )
14391476 . accessibilityLabel ( " Open \( node. title) workflow details " )
14401477 . accessibilityIdentifier ( " workflow-node- \( node. id) " )
14411478 }
@@ -1510,6 +1547,7 @@ struct TerminalViewportContent: View {
15101547 . foregroundStyle ( . white, . black. opacity ( 0.72 ) )
15111548 }
15121549 . buttonStyle ( . plain)
1550+ . clickableCursor ( )
15131551 . offset ( x: 4 , y: - 4 )
15141552 . accessibilityLabel ( " Remove \( attachment. url. lastPathComponent) " )
15151553 }
@@ -1550,13 +1588,15 @@ struct TerminalViewportContent: View {
15501588 . background ( canSend ? Color . white. opacity ( 0.92 ) : . white. opacity ( 0.07 ) , in: Circle ( ) )
15511589 }
15521590 . buttonStyle ( . plain)
1591+ . clickableCursor ( )
15531592 . keyboardShortcut ( . return, modifiers: . command)
15541593 . disabled ( !canSend)
15551594 . help ( " Send to this session (Return or ⌘↩) " )
15561595 . accessibilityLabel ( " Send prompt to \( session. name) " )
15571596 . accessibilityIdentifier ( " send-prompt " )
15581597 }
15591598 . buttonStyle ( . plain)
1599+ . clickableCursor ( )
15601600 . foregroundStyle ( . white. opacity ( 0.46 ) )
15611601 . padding ( . horizontal, 5 )
15621602 . padding ( . vertical, 3 )
@@ -1778,6 +1818,7 @@ private struct PromptTimelineMarker: View {
17781818 . contentShape ( Rectangle ( ) )
17791819 }
17801820 . buttonStyle ( . plain)
1821+ . clickableCursor ( )
17811822 . onHover { hovering in
17821823 if hovering {
17831824 previewDismissalTask? . cancel ( )
@@ -1986,6 +2027,7 @@ private struct ToolBatchRow: View {
19862027 . contentShape ( Rectangle ( ) )
19872028 }
19882029 . buttonStyle ( . plain)
2030+ . clickableCursor ( )
19892031 . accessibilityLabel ( " \( isExpanded ? " Collapse " : " Expand " ) tool batch: \( summary) " )
19902032 . accessibilityIdentifier ( " chat-tool-batch " )
19912033
@@ -2021,6 +2063,7 @@ private struct ToolBatchRow: View {
20212063 . contentShape ( Rectangle ( ) )
20222064 }
20232065 . buttonStyle ( . plain)
2066+ . clickableCursor ( )
20242067 . accessibilityLabel ( " Show tool detail: \( entry. title ?? " Tool " ) " )
20252068 . accessibilityIdentifier ( " chat-tool-call " )
20262069 }
@@ -2058,6 +2101,7 @@ private struct ToolDetailInspector: View {
20582101 . background ( . white. opacity ( 0.07 ) , in: Circle ( ) )
20592102 }
20602103 . buttonStyle ( . plain)
2104+ . clickableCursor ( )
20612105 . accessibilityLabel ( " Close tool details " )
20622106 }
20632107 . foregroundStyle ( . white. opacity ( 0.68 ) )
@@ -2202,6 +2246,7 @@ private struct ChatTranscriptRow: View {
22022246 . contentShape ( Rectangle ( ) )
22032247 }
22042248 . buttonStyle ( . plain)
2249+ . clickableCursor ( )
22052250 . accessibilityLabel ( " Show \( entry. title ?? " tool " ) details " )
22062251 . accessibilityIdentifier ( " chat-tool-call " )
22072252 . background ( . white. opacity ( isHovered ? 0.065 : 0.035 ) , in: RoundedRectangle ( cornerRadius: 9 , style: . continuous) )
@@ -2238,6 +2283,7 @@ private struct ChatTranscriptRow: View {
22382283 . background ( . white. opacity ( 0.05 ) , in: Capsule ( ) )
22392284 }
22402285 . buttonStyle ( . plain)
2286+ . clickableCursor ( )
22412287 . help ( " Preview \( url. path) " )
22422288 . accessibilityLabel ( " Preview \( url. lastPathComponent) " )
22432289 . accessibilityIdentifier ( " chat-file-reference " )
0 commit comments