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

Dashboard: fix job card description wrapping and alignment

Use attributed paragraph style for multiline NSTextField, constrain
description width to the content column, and compute
preferredMaxLayoutWidth from card width without an incorrect button-
strip reserve so wrapped text lays out left-aligned after resize.

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

+ 35 - 5
App for Indeed/Views/DashboardView.swift

@@ -39,6 +39,20 @@ final class DashboardView: NSView, NSTextFieldDelegate {
39
         static let findJobsCTAHighlight = NSColor(srgbRed: 54 / 255, green: 110 / 255, blue: 198 / 255, alpha: 1)
39
         static let findJobsCTAHighlight = NSColor(srgbRed: 54 / 255, green: 110 / 255, blue: 198 / 255, alpha: 1)
40
     }
40
     }
41
 
41
 
42
+    /// Multiline `NSTextField` often ignores `alignment` for wrapped runs; explicit paragraph alignment matches the title.
43
+    private static func jobListingDescriptionAttributedString(_ plain: String) -> NSAttributedString {
44
+        let paragraph = NSMutableParagraphStyle()
45
+        paragraph.alignment = .left
46
+        paragraph.lineBreakMode = .byWordWrapping
47
+        paragraph.baseWritingDirection = .leftToRight
48
+        let font = NSFont.systemFont(ofSize: 13, weight: .regular)
49
+        return NSAttributedString(string: plain, attributes: [
50
+            .font: font,
51
+            .foregroundColor: Theme.secondaryText,
52
+            .paragraphStyle: paragraph
53
+        ])
54
+    }
55
+
42
     private let contentStack = NSStackView()
56
     private let contentStack = NSStackView()
43
     private let chromeContainer = NSView()
57
     private let chromeContainer = NSView()
44
     private let sidebar = NSStackView()
58
     private let sidebar = NSStackView()
@@ -270,16 +284,20 @@ final class DashboardView: NSView, NSTextFieldDelegate {
270
 
284
 
271
     private func updateDescriptionColumnWidths(in stack: NSStackView, containerWidth: CGFloat) {
285
     private func updateDescriptionColumnWidths(in stack: NSStackView, containerWidth: CGFloat) {
272
         guard containerWidth > 1 else { return }
286
         guard containerWidth > 1 else { return }
273
-        let buttonStripReserve: CGFloat = 200
274
-        let fallbackTextColumn = max(1, containerWidth - 32 - buttonStripReserve)
287
+        // Matches `contentColumn` insets on the card (16 leading + 16 trailing). The description spans the full row below the buttons, so never subtract a “button strip” here — a too-narrow `preferredMaxLayoutWidth` inside a wider field makes wrapped `NSTextField` text lay out like a trailing-aligned band after resizes.
288
+        let contentHorizontalInset: CGFloat = 32
275
         var didChange = false
289
         var didChange = false
276
         for card in stack.arrangedSubviews {
290
         for card in stack.arrangedSubviews {
277
             guard let desc = card.viewWithTag(502) as? NSTextField else { continue }
291
             guard let desc = card.viewWithTag(502) as? NSTextField else { continue }
292
+            let cardWidth = card.bounds.width > 1 ? card.bounds.width : containerWidth
293
+            let fallbackColumn = max(1, cardWidth - contentHorizontalInset)
278
             let columnWidth: CGFloat
294
             let columnWidth: CGFloat
279
-            if let column = desc.superview, column.bounds.width > 1 {
295
+            if desc.bounds.width > 1 {
296
+                columnWidth = desc.bounds.width
297
+            } else if let column = desc.superview, column.bounds.width > 1 {
280
                 columnWidth = column.bounds.width
298
                 columnWidth = column.bounds.width
281
             } else {
299
             } else {
282
-                columnWidth = fallbackTextColumn
300
+                columnWidth = fallbackColumn
283
             }
301
             }
284
             if abs(desc.preferredMaxLayoutWidth - columnWidth) > 0.5 {
302
             if abs(desc.preferredMaxLayoutWidth - columnWidth) > 0.5 {
285
                 desc.preferredMaxLayoutWidth = columnWidth
303
                 desc.preferredMaxLayoutWidth = columnWidth
@@ -369,6 +387,16 @@ final class DashboardView: NSView, NSTextFieldDelegate {
369
         descriptionField.font = .systemFont(ofSize: 13, weight: .regular)
387
         descriptionField.font = .systemFont(ofSize: 13, weight: .regular)
370
         descriptionField.textColor = Theme.secondaryText
388
         descriptionField.textColor = Theme.secondaryText
371
         descriptionField.maximumNumberOfLines = 0
389
         descriptionField.maximumNumberOfLines = 0
390
+        descriptionField.alignment = .left
391
+        descriptionField.lineBreakMode = .byWordWrapping
392
+        descriptionField.baseWritingDirection = .leftToRight
393
+        descriptionField.attributedStringValue = Self.jobListingDescriptionAttributedString(job.description)
394
+        if let cell = descriptionField.cell as? NSTextFieldCell {
395
+            cell.alignment = .left
396
+            cell.wraps = true
397
+        }
398
+        descriptionField.setContentHuggingPriority(.defaultLow, for: .horizontal)
399
+        descriptionField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
372
         descriptionField.tag = 502
400
         descriptionField.tag = 502
373
         descriptionField.translatesAutoresizingMaskIntoConstraints = false
401
         descriptionField.translatesAutoresizingMaskIntoConstraints = false
374
 
402
 
@@ -460,7 +488,9 @@ final class DashboardView: NSView, NSTextFieldDelegate {
460
             savedButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 72),
488
             savedButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 72),
461
             savedButton.heightAnchor.constraint(equalToConstant: 28),
489
             savedButton.heightAnchor.constraint(equalToConstant: 28),
462
             dismissButton.widthAnchor.constraint(equalToConstant: 28),
490
             dismissButton.widthAnchor.constraint(equalToConstant: 28),
463
-            dismissButton.heightAnchor.constraint(equalToConstant: 28)
491
+            dismissButton.heightAnchor.constraint(equalToConstant: 28),
492
+
493
+            descriptionField.widthAnchor.constraint(equalTo: contentColumn.widthAnchor)
464
         ])
494
         ])
465
 
495
 
466
         return card
496
         return card