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

Fix CV template gallery cards so names always show fully.

Reserve a fixed footer for the template title, drop the redundant subtitle line, and add display-name fallbacks so AI templates never render blank labels.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 дней назад: 2
Родитель
Сommit
0e84f04468

+ 5 - 3
App for Indeed/Services/AppLocalization.swift

@@ -104,7 +104,8 @@ func appLocalized(_ key: String, language: AppLanguage) -> String {
104
           let bundle = Bundle(path: path) else {
104
           let bundle = Bundle(path: path) else {
105
         return key
105
         return key
106
     }
106
     }
107
-    return bundle.localizedString(forKey: key, value: key, table: nil)
107
+    let value = bundle.localizedString(forKey: key, value: key, table: nil)
108
+    return value.isEmpty ? key : value
108
 }
109
 }
109
 
110
 
110
 func currentAppLanguage() -> AppLanguage {
111
 func currentAppLanguage() -> AppLanguage {
@@ -124,10 +125,11 @@ func localizedTemplateName(_ nameKey: String) -> String {
124
     guard !trimmed.isEmpty else { return nameKey }
125
     guard !trimmed.isEmpty else { return nameKey }
125
 
126
 
126
     let exact = appLocalized(trimmed, language: language)
127
     let exact = appLocalized(trimmed, language: language)
127
-    if exact != trimmed { return exact }
128
+    if !exact.isEmpty, exact != trimmed { return exact }
128
 
129
 
129
     guard language != .english else { return trimmed }
130
     guard language != .english else { return trimmed }
130
-    return translateTemplateNameByTokens(trimmed, language: language)
131
+    let tokenized = translateTemplateNameByTokens(trimmed, language: language)
132
+    return tokenized.isEmpty ? trimmed : tokenized
131
 }
133
 }
132
 
134
 
133
 private func translateTemplateNameByTokens(_ name: String, language: AppLanguage) -> String {
135
 private func translateTemplateNameByTokens(_ name: String, language: AppLanguage) -> String {

+ 1 - 1
App for Indeed/Views/CVFilledPreviewPageView.swift

@@ -260,7 +260,7 @@ final class CVFilledPreviewPageView: NSView {
260
         profileDocumentView = doc
260
         profileDocumentView = doc
261
         contentStack.addArrangedSubview(doc)
261
         contentStack.addArrangedSubview(doc)
262
         let profileTitle = profile.profileDisplayName.isEmpty ? L("Untitled profile") : profile.profileDisplayName
262
         let profileTitle = profile.profileDisplayName.isEmpty ? L("Untitled profile") : profile.profileDisplayName
263
-        titleLabel.stringValue = "\(template.localizedName) · \(profileTitle)"
263
+        titleLabel.stringValue = "\(template.displayName) · \(profileTitle)"
264
     }
264
     }
265
 
265
 
266
     @objc private func didTapBack() {
266
     @objc private func didTapBack() {

+ 29 - 19
App for Indeed/Views/CVMakerPageView.swift

@@ -124,6 +124,15 @@ struct CVTemplate: Hashable {
124
     /// User-facing template title for the active language (`name` is the English localization key).
124
     /// User-facing template title for the active language (`name` is the English localization key).
125
     var localizedName: String { localizedTemplateName(name) }
125
     var localizedName: String { localizedTemplateName(name) }
126
 
126
 
127
+    /// Non-empty label for gallery cards and profile rows.
128
+    var displayName: String {
129
+        let localized = localizedName.trimmingCharacters(in: .whitespacesAndNewlines)
130
+        if !localized.isEmpty { return localized }
131
+        let raw = name.trimmingCharacters(in: .whitespacesAndNewlines)
132
+        if !raw.isEmpty { return raw }
133
+        return id
134
+    }
135
+
127
     /// Optional bundle image name; `nil` means render a live vector/text preview.
136
     /// Optional bundle image name; `nil` means render a live vector/text preview.
128
     var previewImageAssetName: String? { nil }
137
     var previewImageAssetName: String? { nil }
129
 
138
 
@@ -1417,7 +1426,9 @@ private final class CVChipButton: NSView {
1417
 /// Premium gallery card: live résumé thumbnail, soft shadow, and an animated
1426
 /// Premium gallery card: live résumé thumbnail, soft shadow, and an animated
1418
 /// brand border when selected.
1427
 /// brand border when selected.
1419
 private final class CVTemplateCard: NSView {
1428
 private final class CVTemplateCard: NSView {
1420
-    static let layoutHeight: CGFloat = 292
1429
+    private static let footerHeight: CGFloat = 50
1430
+    private static let previewHeight: CGFloat = 242
1431
+    static let layoutHeight: CGFloat = footerHeight + previewHeight
1421
 
1432
 
1422
     var onSelect: (() -> Void)?
1433
     var onSelect: (() -> Void)?
1423
     var isSelected: Bool = false { didSet { applyChrome() } }
1434
     var isSelected: Bool = false { didSet { applyChrome() } }
@@ -1432,7 +1443,6 @@ private final class CVTemplateCard: NSView {
1432
     private let footerView = NSView()
1443
     private let footerView = NSView()
1433
     private let preview: CVTemplatePreviewView
1444
     private let preview: CVTemplatePreviewView
1434
     private let nameLabel = NSTextField(labelWithString: "")
1445
     private let nameLabel = NSTextField(labelWithString: "")
1435
-    private let categoryLabel = NSTextField(labelWithString: "")
1436
     private var trackingArea: NSTrackingArea?
1446
     private var trackingArea: NSTrackingArea?
1437
     private var isHovering: Bool = false
1447
     private var isHovering: Bool = false
1438
     private var didPushCursor: Bool = false
1448
     private var didPushCursor: Bool = false
@@ -1452,42 +1462,43 @@ private final class CVTemplateCard: NSView {
1452
         previewSurface.translatesAutoresizingMaskIntoConstraints = false
1462
         previewSurface.translatesAutoresizingMaskIntoConstraints = false
1453
         previewSurface.wantsLayer = true
1463
         previewSurface.wantsLayer = true
1454
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
1464
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
1465
+        previewSurface.layer?.masksToBounds = true
1455
 
1466
 
1456
         preview.translatesAutoresizingMaskIntoConstraints = false
1467
         preview.translatesAutoresizingMaskIntoConstraints = false
1457
         previewSurface.addSubview(preview)
1468
         previewSurface.addSubview(preview)
1458
 
1469
 
1459
-        refreshLocalizedTitle()
1460
         nameLabel.font = .systemFont(ofSize: 14, weight: .semibold)
1470
         nameLabel.font = .systemFont(ofSize: 14, weight: .semibold)
1461
         nameLabel.textColor = palette.primaryText
1471
         nameLabel.textColor = palette.primaryText
1462
         nameLabel.isBordered = false
1472
         nameLabel.isBordered = false
1463
         nameLabel.drawsBackground = false
1473
         nameLabel.drawsBackground = false
1464
         nameLabel.isEditable = false
1474
         nameLabel.isEditable = false
1465
         nameLabel.isSelectable = false
1475
         nameLabel.isSelectable = false
1476
+        nameLabel.lineBreakMode = .byTruncatingTail
1477
+        nameLabel.maximumNumberOfLines = 1
1478
+        nameLabel.setContentCompressionResistancePriority(.required, for: .vertical)
1479
+        nameLabel.setContentHuggingPriority(.required, for: .vertical)
1480
+        refreshLocalizedTitle()
1466
 
1481
 
1467
-        categoryLabel.font = .systemFont(ofSize: 11.5, weight: .regular)
1468
-        categoryLabel.textColor = palette.secondaryText
1469
-        categoryLabel.isBordered = false
1470
-        categoryLabel.drawsBackground = false
1471
-        categoryLabel.isEditable = false
1472
-        categoryLabel.isSelectable = false
1473
-
1474
-        let footerStack = NSStackView(views: [nameLabel, categoryLabel])
1482
+        let footerStack = NSStackView(views: [nameLabel])
1475
         footerStack.orientation = .vertical
1483
         footerStack.orientation = .vertical
1476
-        footerStack.spacing = 3
1477
         footerStack.alignment = .leading
1484
         footerStack.alignment = .leading
1478
         footerStack.translatesAutoresizingMaskIntoConstraints = false
1485
         footerStack.translatesAutoresizingMaskIntoConstraints = false
1479
 
1486
 
1480
         footerView.translatesAutoresizingMaskIntoConstraints = false
1487
         footerView.translatesAutoresizingMaskIntoConstraints = false
1481
         footerView.wantsLayer = true
1488
         footerView.wantsLayer = true
1482
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
1489
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
1490
+        footerView.setContentCompressionResistancePriority(.required, for: .vertical)
1491
+        footerView.setContentHuggingPriority(.required, for: .vertical)
1483
         footerView.addSubview(footerStack)
1492
         footerView.addSubview(footerStack)
1484
         NSLayoutConstraint.activate([
1493
         NSLayoutConstraint.activate([
1485
             footerStack.leadingAnchor.constraint(equalTo: footerView.leadingAnchor, constant: 16),
1494
             footerStack.leadingAnchor.constraint(equalTo: footerView.leadingAnchor, constant: 16),
1486
             footerStack.trailingAnchor.constraint(lessThanOrEqualTo: footerView.trailingAnchor, constant: -16),
1495
             footerStack.trailingAnchor.constraint(lessThanOrEqualTo: footerView.trailingAnchor, constant: -16),
1487
-            footerStack.topAnchor.constraint(equalTo: footerView.topAnchor, constant: 13),
1488
-            footerStack.bottomAnchor.constraint(equalTo: footerView.bottomAnchor, constant: -13)
1496
+            footerStack.centerYAnchor.constraint(equalTo: footerView.centerYAnchor)
1489
         ])
1497
         ])
1490
 
1498
 
1499
+        previewSurface.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
1500
+        previewSurface.setContentHuggingPriority(.defaultLow, for: .vertical)
1501
+
1491
         addSubview(previewSurface)
1502
         addSubview(previewSurface)
1492
         addSubview(footerView)
1503
         addSubview(footerView)
1493
 
1504
 
@@ -1495,7 +1506,7 @@ private final class CVTemplateCard: NSView {
1495
             previewSurface.topAnchor.constraint(equalTo: topAnchor),
1506
             previewSurface.topAnchor.constraint(equalTo: topAnchor),
1496
             previewSurface.leadingAnchor.constraint(equalTo: leadingAnchor),
1507
             previewSurface.leadingAnchor.constraint(equalTo: leadingAnchor),
1497
             previewSurface.trailingAnchor.constraint(equalTo: trailingAnchor),
1508
             previewSurface.trailingAnchor.constraint(equalTo: trailingAnchor),
1498
-            previewSurface.heightAnchor.constraint(greaterThanOrEqualToConstant: 236),
1509
+            previewSurface.heightAnchor.constraint(equalToConstant: Self.previewHeight),
1499
 
1510
 
1500
             preview.topAnchor.constraint(equalTo: previewSurface.topAnchor, constant: 14),
1511
             preview.topAnchor.constraint(equalTo: previewSurface.topAnchor, constant: 14),
1501
             preview.leadingAnchor.constraint(equalTo: previewSurface.leadingAnchor, constant: 16),
1512
             preview.leadingAnchor.constraint(equalTo: previewSurface.leadingAnchor, constant: 16),
@@ -1505,7 +1516,8 @@ private final class CVTemplateCard: NSView {
1505
             footerView.topAnchor.constraint(equalTo: previewSurface.bottomAnchor),
1516
             footerView.topAnchor.constraint(equalTo: previewSurface.bottomAnchor),
1506
             footerView.leadingAnchor.constraint(equalTo: leadingAnchor),
1517
             footerView.leadingAnchor.constraint(equalTo: leadingAnchor),
1507
             footerView.trailingAnchor.constraint(equalTo: trailingAnchor),
1518
             footerView.trailingAnchor.constraint(equalTo: trailingAnchor),
1508
-            footerView.bottomAnchor.constraint(equalTo: bottomAnchor)
1519
+            footerView.bottomAnchor.constraint(equalTo: bottomAnchor),
1520
+            footerView.heightAnchor.constraint(equalToConstant: Self.footerHeight)
1509
         ])
1521
         ])
1510
         applyChrome()
1522
         applyChrome()
1511
     }
1523
     }
@@ -1516,8 +1528,7 @@ private final class CVTemplateCard: NSView {
1516
     }
1528
     }
1517
 
1529
 
1518
     func refreshLocalizedTitle() {
1530
     func refreshLocalizedTitle() {
1519
-        nameLabel.stringValue = template.localizedName
1520
-        categoryLabel.stringValue = "\(template.category) · \(template.layoutType.gallerySubtitle)"
1531
+        nameLabel.stringValue = template.displayName
1521
     }
1532
     }
1522
 
1533
 
1523
     override func layout() {
1534
     override func layout() {
@@ -1605,7 +1616,6 @@ private final class CVTemplateCard: NSView {
1605
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
1616
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
1606
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
1617
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
1607
         nameLabel.textColor = palette.primaryText
1618
         nameLabel.textColor = palette.primaryText
1608
-        categoryLabel.textColor = palette.secondaryText
1609
         layer?.borderColor = borderColor.cgColor
1619
         layer?.borderColor = borderColor.cgColor
1610
         layer?.borderWidth = uniformBorder
1620
         layer?.borderWidth = uniformBorder
1611
         layer?.shadowColor = NSColor.black.cgColor
1621
         layer?.shadowColor = NSColor.black.cgColor