瀏覽代碼

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 天之前
父節點
當前提交
0e84f04468

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

@@ -104,7 +104,8 @@ func appLocalized(_ key: String, language: AppLanguage) -> String {
104 104
           let bundle = Bundle(path: path) else {
105 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 111
 func currentAppLanguage() -> AppLanguage {
@@ -124,10 +125,11 @@ func localizedTemplateName(_ nameKey: String) -> String {
124 125
     guard !trimmed.isEmpty else { return nameKey }
125 126
 
126 127
     let exact = appLocalized(trimmed, language: language)
127
-    if exact != trimmed { return exact }
128
+    if !exact.isEmpty, exact != trimmed { return exact }
128 129
 
129 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 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 260
         profileDocumentView = doc
261 261
         contentStack.addArrangedSubview(doc)
262 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 266
     @objc private func didTapBack() {

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

@@ -124,6 +124,15 @@ struct CVTemplate: Hashable {
124 124
     /// User-facing template title for the active language (`name` is the English localization key).
125 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 136
     /// Optional bundle image name; `nil` means render a live vector/text preview.
128 137
     var previewImageAssetName: String? { nil }
129 138
 
@@ -1417,7 +1426,9 @@ private final class CVChipButton: NSView {
1417 1426
 /// Premium gallery card: live résumé thumbnail, soft shadow, and an animated
1418 1427
 /// brand border when selected.
1419 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 1433
     var onSelect: (() -> Void)?
1423 1434
     var isSelected: Bool = false { didSet { applyChrome() } }
@@ -1432,7 +1443,6 @@ private final class CVTemplateCard: NSView {
1432 1443
     private let footerView = NSView()
1433 1444
     private let preview: CVTemplatePreviewView
1434 1445
     private let nameLabel = NSTextField(labelWithString: "")
1435
-    private let categoryLabel = NSTextField(labelWithString: "")
1436 1446
     private var trackingArea: NSTrackingArea?
1437 1447
     private var isHovering: Bool = false
1438 1448
     private var didPushCursor: Bool = false
@@ -1452,42 +1462,43 @@ private final class CVTemplateCard: NSView {
1452 1462
         previewSurface.translatesAutoresizingMaskIntoConstraints = false
1453 1463
         previewSurface.wantsLayer = true
1454 1464
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
1465
+        previewSurface.layer?.masksToBounds = true
1455 1466
 
1456 1467
         preview.translatesAutoresizingMaskIntoConstraints = false
1457 1468
         previewSurface.addSubview(preview)
1458 1469
 
1459
-        refreshLocalizedTitle()
1460 1470
         nameLabel.font = .systemFont(ofSize: 14, weight: .semibold)
1461 1471
         nameLabel.textColor = palette.primaryText
1462 1472
         nameLabel.isBordered = false
1463 1473
         nameLabel.drawsBackground = false
1464 1474
         nameLabel.isEditable = false
1465 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 1483
         footerStack.orientation = .vertical
1476
-        footerStack.spacing = 3
1477 1484
         footerStack.alignment = .leading
1478 1485
         footerStack.translatesAutoresizingMaskIntoConstraints = false
1479 1486
 
1480 1487
         footerView.translatesAutoresizingMaskIntoConstraints = false
1481 1488
         footerView.wantsLayer = true
1482 1489
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
1490
+        footerView.setContentCompressionResistancePriority(.required, for: .vertical)
1491
+        footerView.setContentHuggingPriority(.required, for: .vertical)
1483 1492
         footerView.addSubview(footerStack)
1484 1493
         NSLayoutConstraint.activate([
1485 1494
             footerStack.leadingAnchor.constraint(equalTo: footerView.leadingAnchor, constant: 16),
1486 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 1502
         addSubview(previewSurface)
1492 1503
         addSubview(footerView)
1493 1504
 
@@ -1495,7 +1506,7 @@ private final class CVTemplateCard: NSView {
1495 1506
             previewSurface.topAnchor.constraint(equalTo: topAnchor),
1496 1507
             previewSurface.leadingAnchor.constraint(equalTo: leadingAnchor),
1497 1508
             previewSurface.trailingAnchor.constraint(equalTo: trailingAnchor),
1498
-            previewSurface.heightAnchor.constraint(greaterThanOrEqualToConstant: 236),
1509
+            previewSurface.heightAnchor.constraint(equalToConstant: Self.previewHeight),
1499 1510
 
1500 1511
             preview.topAnchor.constraint(equalTo: previewSurface.topAnchor, constant: 14),
1501 1512
             preview.leadingAnchor.constraint(equalTo: previewSurface.leadingAnchor, constant: 16),
@@ -1505,7 +1516,8 @@ private final class CVTemplateCard: NSView {
1505 1516
             footerView.topAnchor.constraint(equalTo: previewSurface.bottomAnchor),
1506 1517
             footerView.leadingAnchor.constraint(equalTo: leadingAnchor),
1507 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 1522
         applyChrome()
1511 1523
     }
@@ -1516,8 +1528,7 @@ private final class CVTemplateCard: NSView {
1516 1528
     }
1517 1529
 
1518 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 1534
     override func layout() {
@@ -1605,7 +1616,6 @@ private final class CVTemplateCard: NSView {
1605 1616
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
1606 1617
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
1607 1618
         nameLabel.textColor = palette.primaryText
1608
-        categoryLabel.textColor = palette.secondaryText
1609 1619
         layer?.borderColor = borderColor.cgColor
1610 1620
         layer?.borderWidth = uniformBorder
1611 1621
         layer?.shadowColor = NSColor.black.cgColor