Parcourir la Source

Add a centered Send button to the job search bar.

Replace the invisible gradient CTA with a blue pill, icon+label stack, and horizontal padding so the control reads clearly at the right of the field.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 il y a 3 semaines
Parent
commit
d5ce030a11
1 fichiers modifiés avec 54 ajouts et 54 suppressions
  1. 54 54
      App for Indeed/Views/DashboardView.swift

+ 54 - 54
App for Indeed/Views/DashboardView.swift

@@ -52,11 +52,8 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
52 52
         static let proAccent = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
53 53
         static let proCTABackground = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
54 54
         static let proCTAText = NSColor(srgbRed: 1, green: 1, blue: 1, alpha: 1)
55
-        /// Slightly lighter blue for the top of the search-bar “Find jobs” pill (reads less flat than a solid fill).
56
-        static let findJobsCTAHighlight = NSColor(srgbRed: 54 / 255, green: 110 / 255, blue: 198 / 255, alpha: 1)
57
-        /// Hover states: darker brand blue, deeper gradient top, stronger tints, and subtle neutral fills used across CTAs, toggles, and the sidebar.
55
+        /// Hover states: darker brand blue, stronger tints, and subtle neutral fills used across CTAs, toggles, and the sidebar.
58 56
         static let brandBlueHover = NSColor(srgbRed: 28 / 255, green: 70 / 255, blue: 140 / 255, alpha: 1)
59
-        static let findJobsCTAHighlightHover = NSColor(srgbRed: 44 / 255, green: 94 / 255, blue: 178 / 255, alpha: 1)
60 57
         static let selectionFillHover = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 0.2)
61 58
         static let neutralHoverFill = NSColor(srgbRed: 240 / 255, green: 240 / 255, blue: 240 / 255, alpha: 1)
62 59
         static let sidebarRowHoverFill = NSColor(srgbRed: 0, green: 0, blue: 0, alpha: 0.04)
@@ -93,9 +90,11 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
93 90
     private let jobSearchIcon = NSImageView()
94 91
     private let jobKeywordsField = NSTextField()
95 92
     private let findJobsButton = HoverableButton()
93
+    private let findJobsCTAPill = HoverableView()
94
+    private let sendIconView = NSImageView()
95
+    private let sendLabel = NSTextField(labelWithString: "Send")
96
+    private let sendContentStack = NSStackView()
96 97
     private let findJobsCTAHost = NSView()
97
-    private let findJobsCTAChrome = HoverableView()
98
-    private var findJobsCTAGradientLayer: CAGradientLayer?
99 98
     private let welcomeHeroHost = NSView()
100 99
     private let welcomeHeroBackgroundView = WelcomeHeroBackgroundView()
101 100
     private lazy var welcomeSparkleCluster: WelcomeSparkleClusterView = {
@@ -201,7 +200,6 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
201 200
     override func layout() {
202 201
         super.layout()
203 202
         updateSearchBarShadowPath()
204
-        findJobsCTAGradientLayer?.frame = findJobsCTAChrome.bounds
205 203
         updateFindJobsCTAShadowPath()
206 204
         updateJobListingDescriptionWidths()
207 205
         updateChatBubbleWidths()
@@ -1084,67 +1082,69 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
1084 1082
         findJobsCTAHost.layer?.shadowOffset = CGSize(width: 0, height: 2)
1085 1083
         findJobsCTAHost.layer?.shadowRadius = 6
1086 1084
 
1087
-        findJobsCTAChrome.translatesAutoresizingMaskIntoConstraints = false
1088
-        findJobsCTAChrome.wantsLayer = true
1089
-        findJobsCTAChrome.layer?.masksToBounds = true
1090
-        findJobsCTAChrome.layer?.cornerRadius = ctaCorner
1085
+        let sendContentPadding: CGFloat = 16
1086
+
1087
+        findJobsCTAPill.translatesAutoresizingMaskIntoConstraints = false
1088
+        findJobsCTAPill.wantsLayer = true
1089
+        findJobsCTAPill.layer?.cornerRadius = ctaCorner
1091 1090
         if #available(macOS 11.0, *) {
1092
-            findJobsCTAChrome.layer?.cornerCurve = .continuous
1091
+            findJobsCTAPill.layer?.cornerCurve = .continuous
1093 1092
         }
1093
+        findJobsCTAPill.layer?.masksToBounds = true
1094
+        findJobsCTAPill.layer?.backgroundColor = Theme.brandBlue.cgColor
1094 1095
 
1095
-        let gradient = CAGradientLayer()
1096
-        gradient.colors = [Theme.findJobsCTAHighlight.cgColor, Theme.brandBlue.cgColor]
1097
-        gradient.startPoint = CGPoint(x: 0.5, y: 1)
1098
-        gradient.endPoint = CGPoint(x: 0.5, y: 0)
1099
-        findJobsCTAChrome.layer?.addSublayer(gradient)
1100
-        findJobsCTAGradientLayer = gradient
1096
+        sendIconView.translatesAutoresizingMaskIntoConstraints = false
1097
+        sendIconView.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 11, weight: .semibold)
1098
+        sendIconView.image = NSImage(systemSymbolName: "paperplane.fill", accessibilityDescription: nil)
1099
+        sendIconView.contentTintColor = Theme.proCTAText
1101 1100
 
1102
-        // Tracks hover over the full pill (the button only covers an inset area), so the gradient darkens whenever the mouse is anywhere over the CTA.
1103
-        findJobsCTAChrome.pointerCursor = true
1104
-        findJobsCTAChrome.hoverHandler = { [weak self] hovering in
1105
-            guard let layer = self?.findJobsCTAGradientLayer else { return }
1106
-            CATransaction.begin()
1107
-            CATransaction.setAnimationDuration(0.15)
1108
-            layer.colors = hovering
1109
-                ? [Theme.findJobsCTAHighlightHover.cgColor, Theme.brandBlueHover.cgColor]
1110
-                : [Theme.findJobsCTAHighlight.cgColor, Theme.brandBlue.cgColor]
1111
-            CATransaction.commit()
1112
-        }
1101
+        sendLabel.font = .systemFont(ofSize: 14, weight: .semibold)
1102
+        sendLabel.textColor = Theme.proCTAText
1103
+        sendLabel.alignment = .center
1104
+
1105
+        sendContentStack.orientation = .horizontal
1106
+        sendContentStack.spacing = 6
1107
+        sendContentStack.alignment = .centerY
1108
+        sendContentStack.translatesAutoresizingMaskIntoConstraints = false
1109
+        sendContentStack.addArrangedSubview(sendIconView)
1110
+        sendContentStack.addArrangedSubview(sendLabel)
1113 1111
 
1114 1112
         findJobsButton.translatesAutoresizingMaskIntoConstraints = false
1115 1113
         findJobsButton.title = ""
1116
-        findJobsButton.image = NSImage(systemSymbolName: "paperplane.fill", accessibilityDescription: nil)
1117
-        findJobsButton.imagePosition = .imageLeading
1118
-        findJobsButton.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 11, weight: .semibold)
1119
-        findJobsButton.attributedTitle = NSAttributedString(
1120
-            string: " Send",
1121
-            attributes: [
1122
-                .font: NSFont.systemFont(ofSize: 14, weight: .semibold),
1123
-                .foregroundColor: Theme.proCTAText,
1124
-                .kern: 0.35
1125
-            ]
1126
-        )
1127
-        findJobsButton.contentTintColor = Theme.proCTAText
1128 1114
         findJobsButton.isBordered = false
1129
-        findJobsButton.bezelStyle = .rounded
1115
+        findJobsButton.bezelStyle = .inline
1130 1116
         findJobsButton.wantsLayer = true
1131 1117
         findJobsButton.layer?.backgroundColor = NSColor.clear.cgColor
1132 1118
         findJobsButton.focusRingType = .none
1119
+        findJobsButton.pointerCursor = true
1133 1120
         findJobsButton.target = self
1134 1121
         findJobsButton.action = #selector(didSubmitSearch)
1135
-        findJobsButton.setContentHuggingPriority(.required, for: .horizontal)
1136
-        findJobsButton.setContentCompressionResistancePriority(.required, for: .horizontal)
1122
+        findJobsButton.setAccessibilityLabel("Send")
1123
+        findJobsButton.hoverHandler = { [weak self] hovering in
1124
+            self?.findJobsCTAPill.layer?.backgroundColor = (hovering ? Theme.brandBlueHover : Theme.brandBlue).cgColor
1125
+        }
1137 1126
 
1138
-        findJobsCTAHost.addSubview(findJobsCTAChrome)
1127
+        findJobsCTAHost.addSubview(findJobsCTAPill)
1128
+        findJobsCTAHost.addSubview(sendContentStack)
1139 1129
         findJobsCTAHost.addSubview(findJobsButton)
1130
+        findJobsCTAHost.setContentHuggingPriority(.required, for: .horizontal)
1131
+        findJobsCTAHost.setContentCompressionResistancePriority(.required, for: .horizontal)
1140 1132
         NSLayoutConstraint.activate([
1141
-            findJobsCTAChrome.leadingAnchor.constraint(equalTo: findJobsCTAHost.leadingAnchor),
1142
-            findJobsCTAChrome.trailingAnchor.constraint(equalTo: findJobsCTAHost.trailingAnchor),
1143
-            findJobsCTAChrome.topAnchor.constraint(equalTo: findJobsCTAHost.topAnchor),
1144
-            findJobsCTAChrome.bottomAnchor.constraint(equalTo: findJobsCTAHost.bottomAnchor),
1133
+            findJobsCTAPill.leadingAnchor.constraint(equalTo: findJobsCTAHost.leadingAnchor),
1134
+            findJobsCTAPill.trailingAnchor.constraint(equalTo: findJobsCTAHost.trailingAnchor),
1135
+            findJobsCTAPill.topAnchor.constraint(equalTo: findJobsCTAHost.topAnchor),
1136
+            findJobsCTAPill.bottomAnchor.constraint(equalTo: findJobsCTAHost.bottomAnchor),
1137
+
1138
+            sendContentStack.centerXAnchor.constraint(equalTo: findJobsCTAPill.centerXAnchor),
1139
+            sendContentStack.centerYAnchor.constraint(equalTo: findJobsCTAPill.centerYAnchor),
1140
+            sendContentStack.leadingAnchor.constraint(greaterThanOrEqualTo: findJobsCTAPill.leadingAnchor, constant: sendContentPadding),
1141
+            sendContentStack.trailingAnchor.constraint(lessThanOrEqualTo: findJobsCTAPill.trailingAnchor, constant: -sendContentPadding),
1142
+
1143
+            sendIconView.widthAnchor.constraint(equalToConstant: 14),
1144
+            sendIconView.heightAnchor.constraint(equalToConstant: 14),
1145 1145
 
1146
-            findJobsButton.leadingAnchor.constraint(equalTo: findJobsCTAHost.leadingAnchor, constant: 14),
1147
-            findJobsButton.trailingAnchor.constraint(equalTo: findJobsCTAHost.trailingAnchor, constant: -14),
1146
+            findJobsButton.leadingAnchor.constraint(equalTo: findJobsCTAHost.leadingAnchor),
1147
+            findJobsButton.trailingAnchor.constraint(equalTo: findJobsCTAHost.trailingAnchor),
1148 1148
             findJobsButton.topAnchor.constraint(equalTo: findJobsCTAHost.topAnchor),
1149 1149
             findJobsButton.bottomAnchor.constraint(equalTo: findJobsCTAHost.bottomAnchor)
1150 1150
         ])
@@ -1159,7 +1159,7 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
1159 1159
 
1160 1160
         let row = NSStackView(views: [keywordsStack, findJobsCTAHost])
1161 1161
         row.orientation = .horizontal
1162
-        row.spacing = 0
1162
+        row.spacing = 10
1163 1163
         row.alignment = .centerY
1164 1164
         row.distribution = .fill
1165 1165
         row.translatesAutoresizingMaskIntoConstraints = false
@@ -1184,7 +1184,7 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
1184 1184
             jobSearchIcon.heightAnchor.constraint(equalToConstant: 18),
1185 1185
 
1186 1186
             findJobsCTAHost.heightAnchor.constraint(equalToConstant: ctaHeight),
1187
-            findJobsCTAHost.widthAnchor.constraint(greaterThanOrEqualToConstant: 112)
1187
+            findJobsCTAHost.widthAnchor.constraint(greaterThanOrEqualTo: sendContentStack.widthAnchor, constant: sendContentPadding * 2)
1188 1188
         ])
1189 1189
         searchCard.hoverHandler = nil
1190 1190
     }
@@ -2355,7 +2355,7 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
2355 2355
     private func setInputEnabled(_ enabled: Bool) {
2356 2356
         jobKeywordsField.isEnabled = enabled
2357 2357
         findJobsButton.isEnabled = enabled
2358
-        findJobsButton.alphaValue = enabled ? 1 : 0.65
2358
+        findJobsCTAHost.alphaValue = enabled ? 1 : 0.65
2359 2359
         clearChatButton.isEnabled = enabled
2360 2360
         clearChatButton.alphaValue = enabled ? 1 : 0.65
2361 2361
         trailingLoadMoreJobsButton?.isEnabled = enabled