Parcourir la Source

Fix Profiles list layout and scroll alignment.

Place profile rows directly under the title and description, and move the empty-state copy and Add button into a footer below the list. Use a flipped scroll document view so short content aligns to the top of the clip view instead of leaving a large gap above it on macOS.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 il y a 3 semaines
Parent
commit
e6c3ceeed5
1 fichiers modifiés avec 32 ajouts et 15 suppressions
  1. 32 15
      App for Indeed/Views/ProfilesListPageView.swift

+ 32 - 15
App for Indeed/Views/ProfilesListPageView.swift

@@ -16,6 +16,11 @@ private enum ProfilesListPalette {
16
     static let destructive = NSColor(srgbRed: 220 / 255, green: 38 / 255, blue: 38 / 255, alpha: 1)
16
     static let destructive = NSColor(srgbRed: 220 / 255, green: 38 / 255, blue: 38 / 255, alpha: 1)
17
 }
17
 }
18
 
18
 
19
+/// Document view for the profiles `NSScrollView`; flipped coordinates keep short content aligned to the top of the clip (avoids a large empty band above the content on macOS).
20
+private final class ProfilesListDocumentView: NSView {
21
+    override var isFlipped: Bool { true }
22
+}
23
+
19
 /// Hub for saved job profiles: list, add, edit (opens editor elsewhere), delete.
24
 /// Hub for saved job profiles: list, add, edit (opens editor elsewhere), delete.
20
 final class ProfilesListPageView: NSView {
25
 final class ProfilesListPageView: NSView {
21
     var onAddProfile: (() -> Void)?
26
     var onAddProfile: (() -> Void)?
@@ -23,7 +28,7 @@ final class ProfilesListPageView: NSView {
23
     var onDeleteProfile: ((UUID) -> Void)?
28
     var onDeleteProfile: ((UUID) -> Void)?
24
 
29
 
25
     private let scrollView = NSScrollView()
30
     private let scrollView = NSScrollView()
26
-    private let documentView = NSView()
31
+    private let documentView = ProfilesListDocumentView()
27
     private let contentStack = NSStackView()
32
     private let contentStack = NSStackView()
28
     private let emptyStateLabel = NSTextField(wrappingLabelWithString: "")
33
     private let emptyStateLabel = NSTextField(wrappingLabelWithString: "")
29
     private let addButton = ProfilesPrimaryButton(title: "Add new profile  →", target: nil, action: nil)
34
     private let addButton = ProfilesPrimaryButton(title: "Add new profile  →", target: nil, action: nil)
@@ -85,12 +90,18 @@ final class ProfilesListPageView: NSView {
85
         addButton.action = #selector(didTapAdd)
90
         addButton.action = #selector(didTapAdd)
86
         addButton.translatesAutoresizingMaskIntoConstraints = false
91
         addButton.translatesAutoresizingMaskIntoConstraints = false
87
 
92
 
88
-        let headerStack = NSStackView(views: [title, subtitle, emptyStateLabel, addButton])
89
-        headerStack.orientation = .vertical
90
-        headerStack.alignment = .leading
91
-        headerStack.spacing = 10
92
-        headerStack.translatesAutoresizingMaskIntoConstraints = false
93
-        headerStack.setCustomSpacing(16, after: subtitle)
93
+        let titleSubtitleStack = NSStackView(views: [title, subtitle])
94
+        titleSubtitleStack.orientation = .vertical
95
+        titleSubtitleStack.alignment = .leading
96
+        titleSubtitleStack.spacing = 10
97
+        titleSubtitleStack.translatesAutoresizingMaskIntoConstraints = false
98
+
99
+        let footerStack = NSStackView(views: [emptyStateLabel, addButton])
100
+        footerStack.orientation = .vertical
101
+        footerStack.alignment = .leading
102
+        footerStack.spacing = 10
103
+        footerStack.translatesAutoresizingMaskIntoConstraints = false
104
+        footerStack.setCustomSpacing(16, after: emptyStateLabel)
94
 
105
 
95
         contentStack.orientation = .vertical
106
         contentStack.orientation = .vertical
96
         contentStack.alignment = .leading
107
         contentStack.alignment = .leading
@@ -98,8 +109,9 @@ final class ProfilesListPageView: NSView {
98
         contentStack.translatesAutoresizingMaskIntoConstraints = false
109
         contentStack.translatesAutoresizingMaskIntoConstraints = false
99
 
110
 
100
         documentView.translatesAutoresizingMaskIntoConstraints = false
111
         documentView.translatesAutoresizingMaskIntoConstraints = false
101
-        documentView.addSubview(headerStack)
112
+        documentView.addSubview(titleSubtitleStack)
102
         documentView.addSubview(contentStack)
113
         documentView.addSubview(contentStack)
114
+        documentView.addSubview(footerStack)
103
 
115
 
104
         scrollView.translatesAutoresizingMaskIntoConstraints = false
116
         scrollView.translatesAutoresizingMaskIntoConstraints = false
105
         scrollView.drawsBackground = false
117
         scrollView.drawsBackground = false
@@ -120,18 +132,23 @@ final class ProfilesListPageView: NSView {
120
             documentView.leftAnchor.constraint(equalTo: scrollView.contentView.leftAnchor),
132
             documentView.leftAnchor.constraint(equalTo: scrollView.contentView.leftAnchor),
121
             documentView.rightAnchor.constraint(equalTo: scrollView.contentView.rightAnchor),
133
             documentView.rightAnchor.constraint(equalTo: scrollView.contentView.rightAnchor),
122
             documentView.topAnchor.constraint(equalTo: scrollView.contentView.topAnchor),
134
             documentView.topAnchor.constraint(equalTo: scrollView.contentView.topAnchor),
123
-            documentView.bottomAnchor.constraint(equalTo: contentStack.bottomAnchor, constant: 32),
135
+            documentView.bottomAnchor.constraint(equalTo: footerStack.bottomAnchor, constant: 32),
124
 
136
 
125
-            headerStack.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 32),
126
-            headerStack.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -32),
127
-            headerStack.topAnchor.constraint(equalTo: documentView.topAnchor, constant: 24),
137
+            titleSubtitleStack.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 32),
138
+            titleSubtitleStack.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -32),
139
+            titleSubtitleStack.topAnchor.constraint(equalTo: documentView.topAnchor, constant: 24),
128
 
140
 
129
             contentStack.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 32),
141
             contentStack.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 32),
130
             contentStack.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -32),
142
             contentStack.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -32),
131
-            contentStack.topAnchor.constraint(equalTo: headerStack.bottomAnchor, constant: 24),
143
+            contentStack.topAnchor.constraint(equalTo: titleSubtitleStack.bottomAnchor, constant: 24),
144
+
145
+            footerStack.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 32),
146
+            footerStack.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -32),
147
+            footerStack.topAnchor.constraint(equalTo: contentStack.bottomAnchor, constant: 24),
132
 
148
 
133
-            headerStack.widthAnchor.constraint(equalTo: documentView.widthAnchor, constant: -64),
134
-            contentStack.widthAnchor.constraint(equalTo: documentView.widthAnchor, constant: -64)
149
+            titleSubtitleStack.widthAnchor.constraint(equalTo: documentView.widthAnchor, constant: -64),
150
+            contentStack.widthAnchor.constraint(equalTo: documentView.widthAnchor, constant: -64),
151
+            footerStack.widthAnchor.constraint(equalTo: documentView.widthAnchor, constant: -64)
135
         ])
152
         ])
136
 
153
 
137
         reloadFromStore()
154
         reloadFromStore()