浏览代码

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 1 月之前
父节点
当前提交
0e84f04468

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

@@ -104,7 +104,8 @@ func appLocalized(_ key: String, language: AppLanguage) -> String {
           let bundle = Bundle(path: path) else {
         return key
     }
-    return bundle.localizedString(forKey: key, value: key, table: nil)
+    let value = bundle.localizedString(forKey: key, value: key, table: nil)
+    return value.isEmpty ? key : value
 }
 
 func currentAppLanguage() -> AppLanguage {
@@ -124,10 +125,11 @@ func localizedTemplateName(_ nameKey: String) -> String {
     guard !trimmed.isEmpty else { return nameKey }
 
     let exact = appLocalized(trimmed, language: language)
-    if exact != trimmed { return exact }
+    if !exact.isEmpty, exact != trimmed { return exact }
 
     guard language != .english else { return trimmed }
-    return translateTemplateNameByTokens(trimmed, language: language)
+    let tokenized = translateTemplateNameByTokens(trimmed, language: language)
+    return tokenized.isEmpty ? trimmed : tokenized
 }
 
 private func translateTemplateNameByTokens(_ name: String, language: AppLanguage) -> String {

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

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

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

@@ -124,6 +124,15 @@ struct CVTemplate: Hashable {
     /// User-facing template title for the active language (`name` is the English localization key).
     var localizedName: String { localizedTemplateName(name) }
 
+    /// Non-empty label for gallery cards and profile rows.
+    var displayName: String {
+        let localized = localizedName.trimmingCharacters(in: .whitespacesAndNewlines)
+        if !localized.isEmpty { return localized }
+        let raw = name.trimmingCharacters(in: .whitespacesAndNewlines)
+        if !raw.isEmpty { return raw }
+        return id
+    }
+
     /// Optional bundle image name; `nil` means render a live vector/text preview.
     var previewImageAssetName: String? { nil }
 
@@ -1417,7 +1426,9 @@ private final class CVChipButton: NSView {
 /// Premium gallery card: live résumé thumbnail, soft shadow, and an animated
 /// brand border when selected.
 private final class CVTemplateCard: NSView {
-    static let layoutHeight: CGFloat = 292
+    private static let footerHeight: CGFloat = 50
+    private static let previewHeight: CGFloat = 242
+    static let layoutHeight: CGFloat = footerHeight + previewHeight
 
     var onSelect: (() -> Void)?
     var isSelected: Bool = false { didSet { applyChrome() } }
@@ -1432,7 +1443,6 @@ private final class CVTemplateCard: NSView {
     private let footerView = NSView()
     private let preview: CVTemplatePreviewView
     private let nameLabel = NSTextField(labelWithString: "")
-    private let categoryLabel = NSTextField(labelWithString: "")
     private var trackingArea: NSTrackingArea?
     private var isHovering: Bool = false
     private var didPushCursor: Bool = false
@@ -1452,42 +1462,43 @@ private final class CVTemplateCard: NSView {
         previewSurface.translatesAutoresizingMaskIntoConstraints = false
         previewSurface.wantsLayer = true
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
+        previewSurface.layer?.masksToBounds = true
 
         preview.translatesAutoresizingMaskIntoConstraints = false
         previewSurface.addSubview(preview)
 
-        refreshLocalizedTitle()
         nameLabel.font = .systemFont(ofSize: 14, weight: .semibold)
         nameLabel.textColor = palette.primaryText
         nameLabel.isBordered = false
         nameLabel.drawsBackground = false
         nameLabel.isEditable = false
         nameLabel.isSelectable = false
+        nameLabel.lineBreakMode = .byTruncatingTail
+        nameLabel.maximumNumberOfLines = 1
+        nameLabel.setContentCompressionResistancePriority(.required, for: .vertical)
+        nameLabel.setContentHuggingPriority(.required, for: .vertical)
+        refreshLocalizedTitle()
 
-        categoryLabel.font = .systemFont(ofSize: 11.5, weight: .regular)
-        categoryLabel.textColor = palette.secondaryText
-        categoryLabel.isBordered = false
-        categoryLabel.drawsBackground = false
-        categoryLabel.isEditable = false
-        categoryLabel.isSelectable = false
-
-        let footerStack = NSStackView(views: [nameLabel, categoryLabel])
+        let footerStack = NSStackView(views: [nameLabel])
         footerStack.orientation = .vertical
-        footerStack.spacing = 3
         footerStack.alignment = .leading
         footerStack.translatesAutoresizingMaskIntoConstraints = false
 
         footerView.translatesAutoresizingMaskIntoConstraints = false
         footerView.wantsLayer = true
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
+        footerView.setContentCompressionResistancePriority(.required, for: .vertical)
+        footerView.setContentHuggingPriority(.required, for: .vertical)
         footerView.addSubview(footerStack)
         NSLayoutConstraint.activate([
             footerStack.leadingAnchor.constraint(equalTo: footerView.leadingAnchor, constant: 16),
             footerStack.trailingAnchor.constraint(lessThanOrEqualTo: footerView.trailingAnchor, constant: -16),
-            footerStack.topAnchor.constraint(equalTo: footerView.topAnchor, constant: 13),
-            footerStack.bottomAnchor.constraint(equalTo: footerView.bottomAnchor, constant: -13)
+            footerStack.centerYAnchor.constraint(equalTo: footerView.centerYAnchor)
         ])
 
+        previewSurface.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
+        previewSurface.setContentHuggingPriority(.defaultLow, for: .vertical)
+
         addSubview(previewSurface)
         addSubview(footerView)
 
@@ -1495,7 +1506,7 @@ private final class CVTemplateCard: NSView {
             previewSurface.topAnchor.constraint(equalTo: topAnchor),
             previewSurface.leadingAnchor.constraint(equalTo: leadingAnchor),
             previewSurface.trailingAnchor.constraint(equalTo: trailingAnchor),
-            previewSurface.heightAnchor.constraint(greaterThanOrEqualToConstant: 236),
+            previewSurface.heightAnchor.constraint(equalToConstant: Self.previewHeight),
 
             preview.topAnchor.constraint(equalTo: previewSurface.topAnchor, constant: 14),
             preview.leadingAnchor.constraint(equalTo: previewSurface.leadingAnchor, constant: 16),
@@ -1505,7 +1516,8 @@ private final class CVTemplateCard: NSView {
             footerView.topAnchor.constraint(equalTo: previewSurface.bottomAnchor),
             footerView.leadingAnchor.constraint(equalTo: leadingAnchor),
             footerView.trailingAnchor.constraint(equalTo: trailingAnchor),
-            footerView.bottomAnchor.constraint(equalTo: bottomAnchor)
+            footerView.bottomAnchor.constraint(equalTo: bottomAnchor),
+            footerView.heightAnchor.constraint(equalToConstant: Self.footerHeight)
         ])
         applyChrome()
     }
@@ -1516,8 +1528,7 @@ private final class CVTemplateCard: NSView {
     }
 
     func refreshLocalizedTitle() {
-        nameLabel.stringValue = template.localizedName
-        categoryLabel.stringValue = "\(template.category) · \(template.layoutType.gallerySubtitle)"
+        nameLabel.stringValue = template.displayName
     }
 
     override func layout() {
@@ -1605,7 +1616,6 @@ private final class CVTemplateCard: NSView {
         previewSurface.layer?.backgroundColor = palette.previewSurface.cgColor
         footerView.layer?.backgroundColor = palette.footerBackground.cgColor
         nameLabel.textColor = palette.primaryText
-        categoryLabel.textColor = palette.secondaryText
         layer?.borderColor = borderColor.cgColor
         layer?.borderWidth = uniformBorder
         layer?.shadowColor = NSColor.black.cgColor