Просмотр исходного кода

Fix profile editor label alignment and LTR layout

MyProfilePageView: use leading alignment and width constraints in
labeledGroup so field titles stay on the left; wrap Personal
Information in a horizontal stack with a flexible spacer.

DashboardView: force left-to-right on nonHomeHost and
profilePageContainer so nested controls align consistently.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 недель назад: 3
Родитель
Сommit
e85f4dd01d
2 измененных файлов с 56 добавлено и 17 удалено
  1. 2 0
      App for Indeed/Views/DashboardView.swift
  2. 54 17
      App for Indeed/Views/MyProfilePageView.swift

+ 2 - 0
App for Indeed/Views/DashboardView.swift

@@ -1185,6 +1185,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1185
         nonHomeHost.wantsLayer = true
1185
         nonHomeHost.wantsLayer = true
1186
         nonHomeHost.layer?.backgroundColor = Theme.mainHostBackground.cgColor
1186
         nonHomeHost.layer?.backgroundColor = Theme.mainHostBackground.cgColor
1187
         nonHomeHost.isHidden = true
1187
         nonHomeHost.isHidden = true
1188
+        nonHomeHost.userInterfaceLayoutDirection = .leftToRight
1188
 
1189
 
1189
         nonHomeGenericContainer.translatesAutoresizingMaskIntoConstraints = false
1190
         nonHomeGenericContainer.translatesAutoresizingMaskIntoConstraints = false
1190
         savedJobsPageContainer.translatesAutoresizingMaskIntoConstraints = false
1191
         savedJobsPageContainer.translatesAutoresizingMaskIntoConstraints = false
@@ -1338,6 +1339,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1338
         profilePageContainer.wantsLayer = true
1339
         profilePageContainer.wantsLayer = true
1339
         profilePageContainer.layer?.backgroundColor = Theme.mainHostBackground.cgColor
1340
         profilePageContainer.layer?.backgroundColor = Theme.mainHostBackground.cgColor
1340
         profilePageContainer.isHidden = true
1341
         profilePageContainer.isHidden = true
1342
+        profilePageContainer.userInterfaceLayoutDirection = .leftToRight
1341
 
1343
 
1342
         myProfilePageView.translatesAutoresizingMaskIntoConstraints = false
1344
         myProfilePageView.translatesAutoresizingMaskIntoConstraints = false
1343
         profilePageContainer.addSubview(myProfilePageView)
1345
         profilePageContainer.addSubview(myProfilePageView)

+ 54 - 17
App for Indeed/Views/MyProfilePageView.swift

@@ -45,6 +45,12 @@ final class MyProfilePageView: NSView {
45
 
45
 
46
     private var lastCompactLayout: Bool?
46
     private var lastCompactLayout: Bool?
47
 
47
 
48
+    /// Force left-to-right geometry so profile fields span the full width even when the window uses RTL layout.
49
+    override var userInterfaceLayoutDirection: NSUserInterfaceLayoutDirection {
50
+        get { .leftToRight }
51
+        set { super.userInterfaceLayoutDirection = .leftToRight }
52
+    }
53
+
48
     override init(frame frameRect: NSRect) {
54
     override init(frame frameRect: NSRect) {
49
         super.init(frame: frameRect)
55
         super.init(frame: frameRect)
50
         setup()
56
         setup()
@@ -63,8 +69,10 @@ final class MyProfilePageView: NSView {
63
     private func setup() {
69
     private func setup() {
64
         wantsLayer = true
70
         wantsLayer = true
65
         layer?.backgroundColor = ProfilePagePalette.pageBackground.cgColor
71
         layer?.backgroundColor = ProfilePagePalette.pageBackground.cgColor
72
+        userInterfaceLayoutDirection = .leftToRight
66
 
73
 
67
         scrollView.translatesAutoresizingMaskIntoConstraints = false
74
         scrollView.translatesAutoresizingMaskIntoConstraints = false
75
+        scrollView.userInterfaceLayoutDirection = .leftToRight
68
         scrollView.hasVerticalScroller = true
76
         scrollView.hasVerticalScroller = true
69
         scrollView.hasHorizontalScroller = false
77
         scrollView.hasHorizontalScroller = false
70
         scrollView.autohidesScrollers = true
78
         scrollView.autohidesScrollers = true
@@ -72,6 +80,7 @@ final class MyProfilePageView: NSView {
72
         scrollView.borderType = .noBorder
80
         scrollView.borderType = .noBorder
73
         scrollView.scrollerStyle = .overlay
81
         scrollView.scrollerStyle = .overlay
74
         scrollView.automaticallyAdjustsContentInsets = false
82
         scrollView.automaticallyAdjustsContentInsets = false
83
+        scrollView.contentView.userInterfaceLayoutDirection = .leftToRight
75
 
84
 
76
         documentView.translatesAutoresizingMaskIntoConstraints = false
85
         documentView.translatesAutoresizingMaskIntoConstraints = false
77
         documentView.userInterfaceLayoutDirection = .leftToRight
86
         documentView.userInterfaceLayoutDirection = .leftToRight
@@ -90,9 +99,12 @@ final class MyProfilePageView: NSView {
90
         formStack.translatesAutoresizingMaskIntoConstraints = false
99
         formStack.translatesAutoresizingMaskIntoConstraints = false
91
         formStack.orientation = .vertical
100
         formStack.orientation = .vertical
92
         formStack.alignment = .width
101
         formStack.alignment = .width
102
+        formStack.distribution = .fill
93
         formStack.spacing = 20
103
         formStack.spacing = 20
94
-        formStack.edgeInsets = NSEdgeInsets(top: 28, left: 28, bottom: 28, right: 28)
104
+        formStack.edgeInsets = NSEdgeInsets(top: 28, left: 22, bottom: 28, right: 22)
95
         formStack.userInterfaceLayoutDirection = .leftToRight
105
         formStack.userInterfaceLayoutDirection = .leftToRight
106
+        formStack.setContentHuggingPriority(.defaultLow, for: .horizontal)
107
+        formStack.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
96
 
108
 
97
         addSubview(scrollView)
109
         addSubview(scrollView)
98
         scrollView.documentView = documentView
110
         scrollView.documentView = documentView
@@ -105,13 +117,14 @@ final class MyProfilePageView: NSView {
105
             scrollView.topAnchor.constraint(equalTo: topAnchor),
117
             scrollView.topAnchor.constraint(equalTo: topAnchor),
106
             scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
118
             scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
107
 
119
 
108
-            documentView.leadingAnchor.constraint(equalTo: scrollView.contentView.leadingAnchor),
109
-            documentView.trailingAnchor.constraint(equalTo: scrollView.contentView.trailingAnchor),
120
+            // Pin left and right to the clip view’s geometric edges so the document spans the full visible
121
+            // width (leading/trailing + width alone can leave a narrow strip on the wrong side in edge cases).
122
+            documentView.leftAnchor.constraint(equalTo: scrollView.contentView.leftAnchor),
123
+            documentView.rightAnchor.constraint(equalTo: scrollView.contentView.rightAnchor),
110
             documentView.topAnchor.constraint(equalTo: scrollView.contentView.topAnchor),
124
             documentView.topAnchor.constraint(equalTo: scrollView.contentView.topAnchor),
111
-            documentView.widthAnchor.constraint(equalTo: scrollView.contentView.widthAnchor),
112
 
125
 
113
-            cardView.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 24),
114
-            cardView.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -24),
126
+            cardView.leadingAnchor.constraint(equalTo: documentView.leadingAnchor, constant: 20),
127
+            cardView.trailingAnchor.constraint(equalTo: documentView.trailingAnchor, constant: -20),
115
             cardView.topAnchor.constraint(equalTo: documentView.topAnchor, constant: 16),
128
             cardView.topAnchor.constraint(equalTo: documentView.topAnchor, constant: 16),
116
             cardView.bottomAnchor.constraint(equalTo: documentView.bottomAnchor, constant: -24),
129
             cardView.bottomAnchor.constraint(equalTo: documentView.bottomAnchor, constant: -24),
117
 
130
 
@@ -185,14 +198,26 @@ final class MyProfilePageView: NSView {
185
         row.addArrangedSubview(right)
198
         row.addArrangedSubview(right)
186
     }
199
     }
187
 
200
 
188
-    private func sectionHeading(_ text: String) -> NSTextField {
201
+    private func sectionHeading(_ text: String) -> NSView {
189
         let label = NSTextField(labelWithString: text)
202
         let label = NSTextField(labelWithString: text)
190
         label.font = .systemFont(ofSize: 15, weight: .semibold)
203
         label.font = .systemFont(ofSize: 15, weight: .semibold)
191
         label.textColor = ProfilePagePalette.primaryText
204
         label.textColor = ProfilePagePalette.primaryText
192
         label.alignment = .left
205
         label.alignment = .left
206
+        label.baseWritingDirection = .leftToRight
193
         label.translatesAutoresizingMaskIntoConstraints = false
207
         label.translatesAutoresizingMaskIntoConstraints = false
194
-        label.setContentHuggingPriority(.defaultLow, for: .horizontal)
195
-        return label
208
+        label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
209
+
210
+        let spacer = NSView()
211
+        spacer.translatesAutoresizingMaskIntoConstraints = false
212
+        spacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
213
+
214
+        let row = NSStackView(views: [label, spacer])
215
+        row.orientation = .horizontal
216
+        row.alignment = .centerY
217
+        row.spacing = 0
218
+        row.userInterfaceLayoutDirection = .leftToRight
219
+        row.translatesAutoresizingMaskIntoConstraints = false
220
+        return row
196
     }
221
     }
197
 
222
 
198
     private func labeledGroup(title: String, field: NSTextField, placeholder: String) -> NSView {
223
     private func labeledGroup(title: String, field: NSTextField, placeholder: String) -> NSView {
@@ -200,7 +225,9 @@ final class MyProfilePageView: NSView {
200
         label.font = .systemFont(ofSize: 12, weight: .medium)
225
         label.font = .systemFont(ofSize: 12, weight: .medium)
201
         label.textColor = ProfilePagePalette.secondaryText
226
         label.textColor = ProfilePagePalette.secondaryText
202
         label.alignment = .left
227
         label.alignment = .left
228
+        label.baseWritingDirection = .leftToRight
203
         label.translatesAutoresizingMaskIntoConstraints = false
229
         label.translatesAutoresizingMaskIntoConstraints = false
230
+        label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
204
 
231
 
205
         styleSingleLineField(field, placeholder: placeholder)
232
         styleSingleLineField(field, placeholder: placeholder)
206
         let wrap = roundedFieldChrome(containing: field, minHeight: 40)
233
         let wrap = roundedFieldChrome(containing: field, minHeight: 40)
@@ -208,12 +235,16 @@ final class MyProfilePageView: NSView {
208
         let stack = NSStackView(views: [label, wrap])
235
         let stack = NSStackView(views: [label, wrap])
209
         stack.orientation = .vertical
236
         stack.orientation = .vertical
210
         stack.spacing = 8
237
         stack.spacing = 8
211
-        stack.alignment = .width
238
+        // Leading keeps the title at the left edge; width match keeps the field full width.
239
+        stack.alignment = .leading
212
         stack.translatesAutoresizingMaskIntoConstraints = false
240
         stack.translatesAutoresizingMaskIntoConstraints = false
213
         stack.userInterfaceLayoutDirection = .leftToRight
241
         stack.userInterfaceLayoutDirection = .leftToRight
214
         stack.setContentHuggingPriority(.defaultLow, for: .horizontal)
242
         stack.setContentHuggingPriority(.defaultLow, for: .horizontal)
215
         wrap.setContentHuggingPriority(.defaultLow, for: .horizontal)
243
         wrap.setContentHuggingPriority(.defaultLow, for: .horizontal)
216
         wrap.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
244
         wrap.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
245
+        NSLayoutConstraint.activate([
246
+            wrap.widthAnchor.constraint(equalTo: stack.widthAnchor)
247
+        ])
217
         return stack
248
         return stack
218
     }
249
     }
219
 
250
 
@@ -236,6 +267,8 @@ final class MyProfilePageView: NSView {
236
         field.cell?.usesSingleLineMode = true
267
         field.cell?.usesSingleLineMode = true
237
         field.cell?.wraps = false
268
         field.cell?.wraps = false
238
         field.cell?.isScrollable = true
269
         field.cell?.isScrollable = true
270
+        field.baseWritingDirection = .leftToRight
271
+        field.alignment = .left
239
     }
272
     }
240
 
273
 
241
     private func roundedFieldChrome(containing field: NSTextField, minHeight: CGFloat) -> NSView {
274
     private func roundedFieldChrome(containing field: NSTextField, minHeight: CGFloat) -> NSView {
@@ -251,8 +284,8 @@ final class MyProfilePageView: NSView {
251
         }
284
         }
252
         wrap.addSubview(field)
285
         wrap.addSubview(field)
253
         NSLayoutConstraint.activate([
286
         NSLayoutConstraint.activate([
254
-            field.leadingAnchor.constraint(equalTo: wrap.leadingAnchor, constant: 12),
255
-            field.trailingAnchor.constraint(equalTo: wrap.trailingAnchor, constant: -12),
287
+            field.leftAnchor.constraint(equalTo: wrap.leftAnchor, constant: 12),
288
+            field.rightAnchor.constraint(equalTo: wrap.rightAnchor, constant: -12),
256
             field.centerYAnchor.constraint(equalTo: wrap.centerYAnchor),
289
             field.centerYAnchor.constraint(equalTo: wrap.centerYAnchor),
257
             wrap.heightAnchor.constraint(greaterThanOrEqualToConstant: minHeight)
290
             wrap.heightAnchor.constraint(greaterThanOrEqualToConstant: minHeight)
258
         ])
291
         ])
@@ -281,6 +314,8 @@ final class MyProfilePageView: NSView {
281
         careerField.stringValue = ""
314
         careerField.stringValue = ""
282
         careerField.setContentHuggingPriority(.defaultLow, for: .horizontal)
315
         careerField.setContentHuggingPriority(.defaultLow, for: .horizontal)
283
         careerField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
316
         careerField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
317
+        careerField.baseWritingDirection = .leftToRight
318
+        careerField.alignment = .left
284
         careerField.placeholderAttributedString = NSAttributedString(
319
         careerField.placeholderAttributedString = NSAttributedString(
285
             string: "Brief overview of your professional background and key achievements...",
320
             string: "Brief overview of your professional background and key achievements...",
286
             attributes: [
321
             attributes: [
@@ -301,8 +336,8 @@ final class MyProfilePageView: NSView {
301
         }
336
         }
302
         wrap.addSubview(careerField)
337
         wrap.addSubview(careerField)
303
         NSLayoutConstraint.activate([
338
         NSLayoutConstraint.activate([
304
-            careerField.leadingAnchor.constraint(equalTo: wrap.leadingAnchor, constant: 12),
305
-            careerField.trailingAnchor.constraint(equalTo: wrap.trailingAnchor, constant: -12),
339
+            careerField.leftAnchor.constraint(equalTo: wrap.leftAnchor, constant: 12),
340
+            careerField.rightAnchor.constraint(equalTo: wrap.rightAnchor, constant: -12),
306
             careerField.topAnchor.constraint(equalTo: wrap.topAnchor, constant: 10),
341
             careerField.topAnchor.constraint(equalTo: wrap.topAnchor, constant: 10),
307
             careerField.bottomAnchor.constraint(equalTo: wrap.bottomAnchor, constant: -10),
342
             careerField.bottomAnchor.constraint(equalTo: wrap.bottomAnchor, constant: -10),
308
             wrap.heightAnchor.constraint(greaterThanOrEqualToConstant: 120)
343
             wrap.heightAnchor.constraint(greaterThanOrEqualToConstant: 120)
@@ -323,6 +358,7 @@ final class MyProfilePageView: NSView {
323
         let title = NSTextField(labelWithString: "Profile Image (Optional)")
358
         let title = NSTextField(labelWithString: "Profile Image (Optional)")
324
         title.font = .systemFont(ofSize: 12, weight: .medium)
359
         title.font = .systemFont(ofSize: 12, weight: .medium)
325
         title.textColor = ProfilePagePalette.secondaryText
360
         title.textColor = ProfilePagePalette.secondaryText
361
+        title.alignment = .left
326
         title.translatesAutoresizingMaskIntoConstraints = false
362
         title.translatesAutoresizingMaskIntoConstraints = false
327
 
363
 
328
         let avatarHost = NSView()
364
         let avatarHost = NSView()
@@ -360,6 +396,7 @@ final class MyProfilePageView: NSView {
360
         let hint = NSTextField(wrappingLabelWithString: "Recommended: Square image, max 2MB")
396
         let hint = NSTextField(wrappingLabelWithString: "Recommended: Square image, max 2MB")
361
         hint.font = .systemFont(ofSize: 11, weight: .regular)
397
         hint.font = .systemFont(ofSize: 11, weight: .regular)
362
         hint.textColor = ProfilePagePalette.secondaryText
398
         hint.textColor = ProfilePagePalette.secondaryText
399
+        hint.alignment = .left
363
         hint.maximumNumberOfLines = 0
400
         hint.maximumNumberOfLines = 0
364
 
401
 
365
         let rightColumn = NSStackView(views: [uploadPhotoButton, hint])
402
         let rightColumn = NSStackView(views: [uploadPhotoButton, hint])
@@ -373,6 +410,7 @@ final class MyProfilePageView: NSView {
373
         row.alignment = .centerY
410
         row.alignment = .centerY
374
         row.spacing = 16
411
         row.spacing = 16
375
         row.translatesAutoresizingMaskIntoConstraints = false
412
         row.translatesAutoresizingMaskIntoConstraints = false
413
+        row.userInterfaceLayoutDirection = .leftToRight
376
 
414
 
377
         let stack = NSStackView(views: [title, row])
415
         let stack = NSStackView(views: [title, row])
378
         stack.orientation = .vertical
416
         stack.orientation = .vertical
@@ -381,7 +419,6 @@ final class MyProfilePageView: NSView {
381
         stack.translatesAutoresizingMaskIntoConstraints = false
419
         stack.translatesAutoresizingMaskIntoConstraints = false
382
         stack.userInterfaceLayoutDirection = .leftToRight
420
         stack.userInterfaceLayoutDirection = .leftToRight
383
         row.setContentHuggingPriority(.defaultLow, for: .horizontal)
421
         row.setContentHuggingPriority(.defaultLow, for: .horizontal)
384
-        row.alignment = .leading
385
         return stack
422
         return stack
386
     }
423
     }
387
 
424
 
@@ -393,10 +430,10 @@ final class MyProfilePageView: NSView {
393
         host.addSubview(saveButton)
430
         host.addSubview(saveButton)
394
         NSLayoutConstraint.activate([
431
         NSLayoutConstraint.activate([
395
             saveButton.leadingAnchor.constraint(equalTo: host.leadingAnchor),
432
             saveButton.leadingAnchor.constraint(equalTo: host.leadingAnchor),
396
-            saveButton.trailingAnchor.constraint(equalTo: host.trailingAnchor),
397
             saveButton.topAnchor.constraint(equalTo: host.topAnchor),
433
             saveButton.topAnchor.constraint(equalTo: host.topAnchor),
398
             saveButton.bottomAnchor.constraint(equalTo: host.bottomAnchor),
434
             saveButton.bottomAnchor.constraint(equalTo: host.bottomAnchor),
399
-            saveButton.heightAnchor.constraint(equalToConstant: 48)
435
+            saveButton.heightAnchor.constraint(equalToConstant: 48),
436
+            saveButton.trailingAnchor.constraint(lessThanOrEqualTo: host.trailingAnchor)
400
         ])
437
         ])
401
         return host
438
         return host
402
     }
439
     }