Преглед изворни кода

Use asset catalog logos in dashboard, loading, and logo views.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 пре 2 месеци
родитељ
комит
3b4bd83a1c

+ 22 - 59
App for Indeed/Views/DashboardView.swift

@@ -97,9 +97,8 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
     private let findJobsCTAHost = NSView()
     private let findJobsCTAHost = NSView()
     private let welcomeHeroHost = NSView()
     private let welcomeHeroHost = NSView()
     private let welcomeHeroBackgroundView = WelcomeHeroBackgroundView()
     private let welcomeHeroBackgroundView = WelcomeHeroBackgroundView()
-    private lazy var welcomeSparkleCluster: WelcomeSparkleClusterView = {
-        WelcomeSparkleClusterView(iconWell: Theme.welcomeHeroIconWell, tint: Theme.welcomeHeroHeadingBlue)
-    }()
+    private let welcomeLogoWell = NSView()
+    private let welcomeLogoView = IndeedLogoView(displayHeight: 40, variant: .compact)
     private let featureCardsRow = NSStackView()
     private let featureCardsRow = NSStackView()
     private let clearChatButton = NSButton(title: "Clear chat", target: nil, action: nil)
     private let clearChatButton = NSButton(title: "Clear chat", target: nil, action: nil)
     private let chatScrollView = NSScrollView()
     private let chatScrollView = NSScrollView()
@@ -290,7 +289,18 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
         welcomeHeroBackgroundView.translatesAutoresizingMaskIntoConstraints = false
         welcomeHeroBackgroundView.translatesAutoresizingMaskIntoConstraints = false
         welcomeHeroBackgroundView.waveTint = Theme.welcomeHeroWaveTint
         welcomeHeroBackgroundView.waveTint = Theme.welcomeHeroWaveTint
 
 
-        let welcomeHeroContent = NSStackView(views: [welcomeSparkleCluster, greetingLabel, subtitleLabel])
+        welcomeLogoWell.translatesAutoresizingMaskIntoConstraints = false
+        welcomeLogoWell.wantsLayer = true
+        welcomeLogoWell.layer?.backgroundColor = Theme.welcomeHeroIconWell.cgColor
+        welcomeLogoWell.layer?.cornerRadius = 28
+        if #available(macOS 11.0, *) {
+            welcomeLogoWell.layer?.cornerCurve = .continuous
+        }
+
+        welcomeLogoView.translatesAutoresizingMaskIntoConstraints = false
+        welcomeLogoWell.addSubview(welcomeLogoView)
+
+        let welcomeHeroContent = NSStackView(views: [welcomeLogoWell, greetingLabel, subtitleLabel])
         welcomeHeroContent.orientation = .vertical
         welcomeHeroContent.orientation = .vertical
         welcomeHeroContent.spacing = 8
         welcomeHeroContent.spacing = 8
         welcomeHeroContent.alignment = .centerX
         welcomeHeroContent.alignment = .centerX
@@ -309,7 +319,12 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
             welcomeHeroContent.leadingAnchor.constraint(greaterThanOrEqualTo: welcomeHeroHost.leadingAnchor, constant: 16),
             welcomeHeroContent.leadingAnchor.constraint(greaterThanOrEqualTo: welcomeHeroHost.leadingAnchor, constant: 16),
             welcomeHeroContent.trailingAnchor.constraint(lessThanOrEqualTo: welcomeHeroHost.trailingAnchor, constant: -16),
             welcomeHeroContent.trailingAnchor.constraint(lessThanOrEqualTo: welcomeHeroHost.trailingAnchor, constant: -16),
             welcomeHeroContent.topAnchor.constraint(equalTo: welcomeHeroHost.topAnchor, constant: 4),
             welcomeHeroContent.topAnchor.constraint(equalTo: welcomeHeroHost.topAnchor, constant: 4),
-            welcomeHeroContent.bottomAnchor.constraint(equalTo: welcomeHeroHost.bottomAnchor, constant: -2)
+            welcomeHeroContent.bottomAnchor.constraint(equalTo: welcomeHeroHost.bottomAnchor, constant: -2),
+
+            welcomeLogoWell.widthAnchor.constraint(equalToConstant: 56),
+            welcomeLogoWell.heightAnchor.constraint(equalToConstant: 56),
+            welcomeLogoView.centerXAnchor.constraint(equalTo: welcomeLogoWell.centerXAnchor),
+            welcomeLogoView.centerYAnchor.constraint(equalTo: welcomeLogoWell.centerYAnchor)
         ])
         ])
 
 
         configureFeatureShortcutCards()
         configureFeatureShortcutCards()
@@ -2361,11 +2376,11 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
             $0.removeFromSuperview()
             $0.removeFromSuperview()
         }
         }
 
 
-        let logo = IndeedLogoView(displayHeight: 26)
+        let logo = IndeedLogoView(displayHeight: 34, variant: .compact)
         logo.translatesAutoresizingMaskIntoConstraints = false
         logo.translatesAutoresizingMaskIntoConstraints = false
 
 
         let brand = NSTextField(labelWithString: AppMarketingLinks.appDisplayName)
         let brand = NSTextField(labelWithString: AppMarketingLinks.appDisplayName)
-        brand.font = .systemFont(ofSize: 15, weight: .semibold)
+        brand.font = .systemFont(ofSize: 14, weight: .semibold)
         brand.textColor = Theme.brandBlue
         brand.textColor = Theme.brandBlue
         brand.alignment = .left
         brand.alignment = .left
         brand.maximumNumberOfLines = 2
         brand.maximumNumberOfLines = 2
@@ -3149,58 +3164,6 @@ private final class WelcomeHeroBackgroundView: NSView {
     }
     }
 }
 }
 
 
-/// Circular pastel well with three sparkle symbols (reference: layered stars of different sizes).
-private final class WelcomeSparkleClusterView: NSView {
-    private let diameter: CGFloat = 56
-
-    override var intrinsicContentSize: NSSize {
-        NSSize(width: diameter, height: diameter)
-    }
-
-    init(iconWell: NSColor, tint: NSColor) {
-        super.init(frame: .zero)
-        translatesAutoresizingMaskIntoConstraints = false
-        wantsLayer = true
-        layer?.cornerRadius = diameter / 2
-        if #available(macOS 11.0, *) {
-            layer?.cornerCurve = .continuous
-        }
-        layer?.backgroundColor = iconWell.cgColor
-
-        let configs: [(CGFloat, NSFont.Weight, CGFloat, CGFloat)] = [
-            (17, .medium, 0, 0),
-            (11, .regular, -11, -9),
-            (9, .regular, 12, 10)
-        ]
-
-        let symbolName = Self.sparkleSymbolName()
-        for (size, weight, ox, oy) in configs {
-            let iv = NSImageView()
-            iv.translatesAutoresizingMaskIntoConstraints = false
-            iv.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: size, weight: weight)
-            iv.image = NSImage(systemSymbolName: symbolName, accessibilityDescription: nil)
-            iv.contentTintColor = tint
-            addSubview(iv)
-            NSLayoutConstraint.activate([
-                iv.centerXAnchor.constraint(equalTo: centerXAnchor, constant: ox),
-                iv.centerYAnchor.constraint(equalTo: centerYAnchor, constant: oy)
-            ])
-        }
-    }
-
-    private static func sparkleSymbolName() -> String {
-        if NSImage(systemSymbolName: "sparkle", accessibilityDescription: nil) != nil {
-            return "sparkle"
-        }
-        return "sparkles"
-    }
-
-    @available(*, unavailable)
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
 /// Home welcome row: three tappable shortcuts that seed the main search field (reference: white cards, pastel icon well, arrow at bottom trailing).
 /// Home welcome row: three tappable shortcuts that seed the main search field (reference: white cards, pastel icon well, arrow at bottom trailing).
 private final class FeatureShortcutCardView: NSView {
 private final class FeatureShortcutCardView: NSView {
     private static let cardCornerRadius: CGFloat = 14
     private static let cardCornerRadius: CGFloat = 14

+ 32 - 36
App for Indeed/Views/IndeedLogoView.swift

@@ -5,46 +5,36 @@
 
 
 import Cocoa
 import Cocoa
 
 
-/// Indeed wordmark (`indeed` in brand blue) for splash and branding surfaces.
+/// App logo from the asset catalog for splash and branding surfaces.
 enum IndeedBrandLogo {
 enum IndeedBrandLogo {
-    static let brandBlue = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
+    enum Variant {
+        case standard
+        case compact
+    }
 
 
-    static func wordmarkImage(fittingHeight height: CGFloat) -> NSImage {
-        let fontSize = height * 0.92
-        let font = NSFont.systemFont(ofSize: fontSize, weight: .heavy)
-        let text = "indeed" as NSString
-        let attributes: [NSAttributedString.Key: Any] = [
-            .font: font,
-            .foregroundColor: brandBlue,
-            .kern: -0.6
-        ]
-        let size = text.size(withAttributes: attributes)
-        let canvas = NSSize(width: ceil(size.width) + 4, height: ceil(size.height) + 4)
-        let image = NSImage(size: canvas)
-        image.lockFocus()
-        defer { image.unlockFocus() }
-        NSColor.clear.set()
-        NSRect(origin: .zero, size: canvas).fill()
-        let origin = NSPoint(x: 2, y: (canvas.height - size.height) / 2)
-        text.draw(at: origin, withAttributes: attributes)
-        return image
+    static func logoImage(variant: Variant = .standard) -> NSImage? {
+        switch variant {
+        case .standard:
+            NSImage(named: NSImage.Name("IndeedLogo"))
+        case .compact:
+            NSImage(named: NSImage.Name("IndeedLogoSmall"))
+        }
     }
     }
 }
 }
 
 
 final class IndeedLogoView: NSView {
 final class IndeedLogoView: NSView {
     private let imageView = NSImageView()
     private let imageView = NSImageView()
-    private var displayHeight: CGFloat = 44
+    private let variant: IndeedBrandLogo.Variant
+    private var displayHeight: CGFloat
+    private var sizeConstraints: [NSLayoutConstraint] = []
 
 
     override var intrinsicContentSize: NSSize {
     override var intrinsicContentSize: NSSize {
-        guard let image = imageView.image, image.size.height > 0 else {
-            return NSSize(width: 140, height: displayHeight)
-        }
-        let aspect = image.size.width / image.size.height
-        return NSSize(width: displayHeight * aspect, height: displayHeight)
+        NSSize(width: displayHeight, height: displayHeight)
     }
     }
 
 
-    init(displayHeight: CGFloat = 44) {
+    init(displayHeight: CGFloat = 44, variant: IndeedBrandLogo.Variant = .standard) {
         self.displayHeight = displayHeight
         self.displayHeight = displayHeight
+        self.variant = variant
         super.init(frame: .zero)
         super.init(frame: .zero)
         setUp()
         setUp()
     }
     }
@@ -56,28 +46,34 @@ final class IndeedLogoView: NSView {
 
 
     func setDisplayHeight(_ height: CGFloat) {
     func setDisplayHeight(_ height: CGFloat) {
         displayHeight = height
         displayHeight = height
-        refreshImage()
+        sizeConstraints.forEach { $0.constant = height }
         invalidateIntrinsicContentSize()
         invalidateIntrinsicContentSize()
     }
     }
 
 
     private func setUp() {
     private func setUp() {
         translatesAutoresizingMaskIntoConstraints = false
         translatesAutoresizingMaskIntoConstraints = false
+        setContentHuggingPriority(.required, for: .horizontal)
+        setContentHuggingPriority(.required, for: .vertical)
+        setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
+        setContentCompressionResistancePriority(.defaultLow, for: .vertical)
+
         imageView.translatesAutoresizingMaskIntoConstraints = false
         imageView.translatesAutoresizingMaskIntoConstraints = false
         imageView.imageScaling = .scaleProportionallyUpOrDown
         imageView.imageScaling = .scaleProportionallyUpOrDown
+        imageView.image = IndeedBrandLogo.logoImage(variant: variant)
         addSubview(imageView)
         addSubview(imageView)
-        NSLayoutConstraint.activate([
+
+        let width = widthAnchor.constraint(equalToConstant: displayHeight)
+        let height = heightAnchor.constraint(equalToConstant: displayHeight)
+        sizeConstraints = [width, height]
+
+        NSLayoutConstraint.activate(sizeConstraints + [
             imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
             imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
             imageView.trailingAnchor.constraint(equalTo: trailingAnchor),
             imageView.trailingAnchor.constraint(equalTo: trailingAnchor),
             imageView.topAnchor.constraint(equalTo: topAnchor),
             imageView.topAnchor.constraint(equalTo: topAnchor),
             imageView.bottomAnchor.constraint(equalTo: bottomAnchor)
             imageView.bottomAnchor.constraint(equalTo: bottomAnchor)
         ])
         ])
-        refreshImage()
         setAccessibilityElement(true)
         setAccessibilityElement(true)
         setAccessibilityRole(.image)
         setAccessibilityRole(.image)
-        setAccessibilityLabel("Indeed")
-    }
-
-    private func refreshImage() {
-        imageView.image = IndeedBrandLogo.wordmarkImage(fittingHeight: displayHeight)
+        setAccessibilityLabel(AppMarketingLinks.displayName)
     }
     }
 }
 }

+ 3 - 3
App for Indeed/Views/LoadingView.swift

@@ -24,7 +24,7 @@ final class LoadingView: NSView {
     private let backgroundGradientHost = NSView()
     private let backgroundGradientHost = NSView()
     private let heroBackground = LoadingSplashBackgroundView()
     private let heroBackground = LoadingSplashBackgroundView()
     private let iconWell = NSView()
     private let iconWell = NSView()
-    private let logoView = IndeedLogoView(displayHeight: 44)
+    private let logoView = IndeedLogoView(displayHeight: 40, variant: .compact)
     private let aiBadgeHost = NSView()
     private let aiBadgeHost = NSView()
     private let aiBadgeLabel = NSTextField(labelWithString: "AI-POWERED")
     private let aiBadgeLabel = NSTextField(labelWithString: "AI-POWERED")
     private let titleLabel = NSTextField(labelWithString: AppMarketingLinks.displayName)
     private let titleLabel = NSTextField(labelWithString: AppMarketingLinks.displayName)
@@ -185,8 +185,8 @@ final class LoadingView: NSView {
             heroBackground.topAnchor.constraint(equalTo: topAnchor),
             heroBackground.topAnchor.constraint(equalTo: topAnchor),
             heroBackground.bottomAnchor.constraint(equalTo: bottomAnchor),
             heroBackground.bottomAnchor.constraint(equalTo: bottomAnchor),
 
 
-            iconWell.widthAnchor.constraint(greaterThanOrEqualToConstant: 200),
-            iconWell.heightAnchor.constraint(equalToConstant: 96),
+            iconWell.widthAnchor.constraint(greaterThanOrEqualToConstant: 160),
+            iconWell.heightAnchor.constraint(equalToConstant: 80),
 
 
             logoView.centerXAnchor.constraint(equalTo: iconWell.centerXAnchor),
             logoView.centerXAnchor.constraint(equalTo: iconWell.centerXAnchor),
             logoView.centerYAnchor.constraint(equalTo: iconWell.centerYAnchor),
             logoView.centerYAnchor.constraint(equalTo: iconWell.centerYAnchor),