Explorar el Código

Remove home status banner from dashboard

Drop the light-blue status strip above chat (label, thinking indicator,
brand row, and related layout/animation). Job search flow still uses
inline chat thinking rows; status text updates tied to the banner are
removed.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 hace 2 meses
padre
commit
d0596f75f7
Se han modificado 1 ficheros con 0 adiciones y 228 borrados
  1. 0 228
      App for Indeed/Views/DashboardView.swift

+ 0 - 228
App for Indeed/Views/DashboardView.swift

@@ -29,8 +29,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         static let secondaryText = NSColor(srgbRed: 118 / 255, green: 118 / 255, blue: 118 / 255, alpha: 1)
         static let tertiaryText = NSColor(srgbRed: 118 / 255, green: 118 / 255, blue: 118 / 255, alpha: 1)
         static let border = NSColor(srgbRed: 212 / 255, green: 210 / 255, blue: 208 / 255, alpha: 1)
-        /// Home status strip and soft accents (light blue panel in the reference UI).
-        static let statusBannerBackground = NSColor(srgbRed: 232 / 255, green: 242 / 255, blue: 252 / 255, alpha: 1)
         static let featureIconWell = NSColor(srgbRed: 220 / 255, green: 235 / 255, blue: 252 / 255, alpha: 1)
         /// Job search bar outer stroke (soft blue-gray, pill field in the reference UI).
         static let searchBarBorder = NSColor(srgbRed: 180 / 255, green: 200 / 255, blue: 228 / 255, alpha: 1)
@@ -84,16 +82,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
     private let findJobsCTAHost = NSView()
     private let findJobsCTAChrome = HoverableView()
     private var findJobsCTAGradientLayer: CAGradientLayer?
-    private let statusBannerContainer = NSView()
-    private let statusBannerInner = NSView()
-    private let statusBannerRow = NSStackView()
-    private let chatStatusSymbolContainer = NSView()
-    private let chatStatusIcon = NSImageView()
-    private let bannerChatThinkingIndicator = ChatThinkingIndicatorView(compact: true)
-    private let chatStatusLabel = NSTextField(wrappingLabelWithString: "Opening the vault...")
-    private let statusBrandTrailing = NSStackView()
-    private let statusBrandStarIcon = NSImageView()
-    private let statusBrandLabel = NSTextField(labelWithString: "AI Job Finder")
     private let welcomeSparkleIcon = NSImageView()
     private let featureCardsRow = NSStackView()
     private let chatScrollView = NSScrollView()
@@ -126,7 +114,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
     private var isAwaitingResponse = false
     /// Shown under the latest user message while a job search request is in flight.
     private var chatThinkingRowHost: NSView?
-    private var chatStatusSymbolWidthConstraint: NSLayoutConstraint?
     private let jobSearchService = OpenAIJobSearchService()
 
     /// Upper bound sent to the model per request (was fixed at 8 in the prompt). Clamped when calling the API.
@@ -138,9 +125,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         min(jobsPerSearchMaxCap, max(jobsPerSearchMin, requested))
     }
 
-    private static let chatStatusSparklePulseKey = "chatStatusSparklePulse"
-    /// Status label value while the model/API is working; drives the thinking affordance in the banner and chat.
-    private static let chatStatusLoadingMessage = "Searching…"
     private static let welcomeSubtitleBreathKey = "welcomeSubtitleBreath"
 
     override init(frame frameRect: NSRect) {
@@ -160,7 +144,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         updateFindJobsCTAShadowPath()
         updateJobListingDescriptionWidths()
         updateChatBubbleWidths()
-        updateStatusBannerLabelWidth()
     }
 
     func render(_ data: DashboardData) {
@@ -270,7 +253,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         mainOverlay.addArrangedSubview(titleBlock)
         mainOverlay.addArrangedSubview(featureCardsRow)
         mainOverlay.addArrangedSubview(midSpacer)
-        mainOverlay.addArrangedSubview(statusBannerContainer)
         mainOverlay.addArrangedSubview(chatTopSpacer)
         mainOverlay.addArrangedSubview(chatScrollView)
         mainOverlay.addArrangedSubview(chatBottomSpacer)
@@ -304,7 +286,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
             nonHomeHost.bottomAnchor.constraint(equalTo: mainHost.bottomAnchor, constant: -24),
 
             searchBarShadowHost.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
-            statusBannerContainer.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
             featureCardsRow.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
             chatScrollView.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
 
@@ -340,111 +321,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
     }
 
     private func configureChatViews() {
-        statusBannerContainer.translatesAutoresizingMaskIntoConstraints = false
-        statusBannerContainer.setContentHuggingPriority(.defaultHigh, for: .vertical)
-
-        statusBannerInner.translatesAutoresizingMaskIntoConstraints = false
-        statusBannerInner.wantsLayer = true
-        statusBannerInner.layer?.backgroundColor = Theme.statusBannerBackground.cgColor
-        statusBannerInner.layer?.cornerRadius = 14
-        if #available(macOS 11.0, *) {
-            statusBannerInner.layer?.cornerCurve = .continuous
-        }
-        statusBannerInner.layer?.masksToBounds = true
-
-        statusBannerContainer.addSubview(statusBannerInner)
-
-        statusBannerRow.orientation = .horizontal
-        statusBannerRow.spacing = 12
-        statusBannerRow.alignment = .top
-        statusBannerRow.translatesAutoresizingMaskIntoConstraints = false
-
-        chatStatusSymbolContainer.translatesAutoresizingMaskIntoConstraints = false
-        chatStatusSymbolContainer.wantsLayer = true
-        chatStatusSymbolContainer.layer?.backgroundColor = Theme.brandBlue.cgColor
-        chatStatusSymbolContainer.layer?.cornerRadius = 20
-
-        chatStatusIcon.translatesAutoresizingMaskIntoConstraints = false
-        chatStatusIcon.wantsLayer = true
-        chatStatusIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 15, weight: .semibold)
-        chatStatusIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: "Assistant status")
-        chatStatusIcon.contentTintColor = .white
-
-        bannerChatThinkingIndicator.translatesAutoresizingMaskIntoConstraints = false
-        bannerChatThinkingIndicator.isHidden = true
-
-        chatStatusSymbolContainer.addSubview(chatStatusIcon)
-        chatStatusSymbolContainer.addSubview(bannerChatThinkingIndicator)
-
-        let symbolWidth = chatStatusSymbolContainer.widthAnchor.constraint(equalToConstant: 40)
-        chatStatusSymbolWidthConstraint = symbolWidth
-
-        NSLayoutConstraint.activate([
-            symbolWidth,
-            chatStatusSymbolContainer.heightAnchor.constraint(equalToConstant: 40),
-            chatStatusIcon.centerXAnchor.constraint(equalTo: chatStatusSymbolContainer.centerXAnchor),
-            chatStatusIcon.centerYAnchor.constraint(equalTo: chatStatusSymbolContainer.centerYAnchor),
-            bannerChatThinkingIndicator.centerXAnchor.constraint(equalTo: chatStatusSymbolContainer.centerXAnchor),
-            bannerChatThinkingIndicator.centerYAnchor.constraint(equalTo: chatStatusSymbolContainer.centerYAnchor)
-        ])
-
-        chatStatusLabel.font = .systemFont(ofSize: 13, weight: .regular)
-        chatStatusLabel.textColor = Theme.primaryText
-        chatStatusLabel.alignment = .left
-        chatStatusLabel.maximumNumberOfLines = 0
-        chatStatusLabel.lineBreakMode = .byWordWrapping
-        chatStatusLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
-        chatStatusLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
-        chatStatusLabel.translatesAutoresizingMaskIntoConstraints = false
-
-        statusBrandStarIcon.translatesAutoresizingMaskIntoConstraints = false
-        statusBrandStarIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
-        statusBrandStarIcon.image = NSImage(systemSymbolName: "sparkle", accessibilityDescription: nil)
-        statusBrandStarIcon.contentTintColor = Theme.brandBlue
-
-        statusBrandLabel.font = .systemFont(ofSize: 12, weight: .semibold)
-        statusBrandLabel.textColor = Theme.brandBlue
-        statusBrandLabel.alignment = .right
-        statusBrandLabel.maximumNumberOfLines = 1
-
-        statusBrandTrailing.orientation = .horizontal
-        statusBrandTrailing.spacing = 5
-        statusBrandTrailing.alignment = .centerY
-        statusBrandTrailing.translatesAutoresizingMaskIntoConstraints = false
-        statusBrandTrailing.addArrangedSubview(statusBrandStarIcon)
-        statusBrandTrailing.addArrangedSubview(statusBrandLabel)
-        statusBrandTrailing.setContentHuggingPriority(.required, for: .horizontal)
-        statusBrandTrailing.setContentCompressionResistancePriority(.required, for: .horizontal)
-
-        statusBannerRow.addArrangedSubview(chatStatusSymbolContainer)
-        statusBannerRow.addArrangedSubview(chatStatusLabel)
-
-        statusBannerInner.addSubview(statusBannerRow)
-        statusBannerContainer.addSubview(statusBannerInner)
-        statusBannerContainer.addSubview(statusBrandTrailing)
-        statusBannerInner.setContentHuggingPriority(.defaultHigh, for: .horizontal)
-        statusBannerInner.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
-
-        NSLayoutConstraint.activate([
-            statusBannerInner.leadingAnchor.constraint(equalTo: statusBannerContainer.leadingAnchor),
-            statusBannerInner.topAnchor.constraint(equalTo: statusBannerContainer.topAnchor),
-            statusBannerInner.bottomAnchor.constraint(equalTo: statusBannerContainer.bottomAnchor),
-            statusBannerInner.trailingAnchor.constraint(lessThanOrEqualTo: statusBrandTrailing.leadingAnchor, constant: -16),
-
-            statusBrandTrailing.trailingAnchor.constraint(equalTo: statusBannerContainer.trailingAnchor),
-            statusBrandTrailing.centerYAnchor.constraint(equalTo: statusBannerContainer.centerYAnchor),
-
-            statusBannerRow.leadingAnchor.constraint(equalTo: statusBannerInner.leadingAnchor, constant: 14),
-            statusBannerRow.trailingAnchor.constraint(equalTo: statusBannerInner.trailingAnchor, constant: -16),
-            statusBannerRow.topAnchor.constraint(equalTo: statusBannerInner.topAnchor, constant: 10),
-            statusBannerRow.bottomAnchor.constraint(equalTo: statusBannerInner.bottomAnchor, constant: -10),
-
-            statusBannerContainer.heightAnchor.constraint(greaterThanOrEqualToConstant: 52)
-        ])
-
-        syncChatStatusLoadingIndicator(forStatusText: chatStatusLabel.stringValue)
-        syncChatStatusBannerVisuals(forStatusText: chatStatusLabel.stringValue)
-
         chatDocumentView.translatesAutoresizingMaskIntoConstraints = false
         chatStack.orientation = .vertical
         chatStack.spacing = 18
@@ -479,66 +355,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         ])
     }
 
-    private func setChatStatusLabel(_ text: String) {
-        chatStatusLabel.stringValue = text
-        syncChatStatusLoadingIndicator(forStatusText: text)
-        syncChatStatusBannerVisuals(forStatusText: text)
-        syncChatStatusSparkleAnimation()
-        updateStatusBannerLabelWidth()
-    }
-
-    private func updateStatusBannerLabelWidth() {
-        guard statusBannerContainer.bounds.width > 1 else { return }
-        let trailingWidth = max(96, statusBrandTrailing.fittingSize.width)
-        let symbolChrome = chatStatusSymbolWidthConstraint?.constant ?? 40
-        let chrome: CGFloat = 14 + symbolChrome + 12 + 16 + 16 + trailingWidth
-        let target = max(80, statusBannerContainer.bounds.width - chrome)
-        if abs(chatStatusLabel.preferredMaxLayoutWidth - target) > 0.5 {
-            chatStatusLabel.preferredMaxLayoutWidth = target
-            chatStatusLabel.invalidateIntrinsicContentSize()
-        }
-    }
-
-    /// Leading status glyph: sparkles for prompts, magnifying glass for search-result summaries and errors.
-    private func syncChatStatusBannerVisuals(forStatusText text: String) {
-        if text == Self.chatStatusLoadingMessage { return }
-        let lower = text.lowercased()
-        let useMagnifyingGlass =
-            text.hasPrefix("Found ")
-            || text.hasPrefix("Here are")
-            || text.hasPrefix("No jobs")
-            || text.contains("couldn't find")
-            || lower.contains("try again")
-            || lower.contains("could not reach")
-            || lower.contains("search did not finish")
-        let config = NSImage.SymbolConfiguration(pointSize: 15, weight: .semibold)
-        chatStatusIcon.symbolConfiguration = config
-        if useMagnifyingGlass {
-            chatStatusIcon.image = NSImage(systemSymbolName: "magnifyingglass", accessibilityDescription: "Search status")
-        } else {
-            chatStatusIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: "Assistant status")
-        }
-        chatStatusIcon.contentTintColor = .white
-        chatStatusSymbolContainer.layer?.backgroundColor = Theme.brandBlue.cgColor
-    }
-
-    private func syncChatStatusLoadingIndicator(forStatusText text: String) {
-        let loading = (text == Self.chatStatusLoadingMessage)
-        if loading {
-            chatStatusIcon.isHidden = true
-            bannerChatThinkingIndicator.isHidden = false
-            bannerChatThinkingIndicator.startAnimatingIfNeeded()
-            chatStatusSymbolContainer.layer?.backgroundColor = NSColor.clear.cgColor
-            chatStatusSymbolWidthConstraint?.constant = 56
-        } else {
-            bannerChatThinkingIndicator.stopAnimating()
-            bannerChatThinkingIndicator.isHidden = true
-            chatStatusIcon.isHidden = false
-            chatStatusSymbolWidthConstraint?.constant = 40
-            chatStatusSymbolContainer.layer?.backgroundColor = Theme.brandBlue.cgColor
-        }
-    }
-
     private func isWelcomeHeroVisible() -> Bool {
         !mainOverlay.isHidden
     }
@@ -547,37 +363,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         NSWorkspace.shared.accessibilityDisplayShouldReduceMotion
     }
 
-    private func shouldAnimateChatStatusSparkles(for statusText: String) -> Bool {
-        statusText == "Ask me to find jobs"
-            || statusText == "Opening the vault..."
-    }
-
-    private func syncChatStatusSparkleAnimation() {
-        guard !prefersReducedMotion else {
-            stopChatStatusSparkleAnimation()
-            return
-        }
-        guard isWelcomeHeroVisible(), shouldAnimateChatStatusSparkles(for: chatStatusLabel.stringValue) else {
-            stopChatStatusSparkleAnimation()
-            return
-        }
-        guard let layer = chatStatusIcon.layer, layer.animation(forKey: Self.chatStatusSparklePulseKey) == nil else { return }
-
-        let scale = CABasicAnimation(keyPath: "transform.scale")
-        scale.fromValue = 1.0
-        scale.toValue = 1.1
-        scale.duration = 1.25
-        scale.autoreverses = true
-        scale.repeatCount = .greatestFiniteMagnitude
-        scale.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
-        layer.add(scale, forKey: Self.chatStatusSparklePulseKey)
-    }
-
-    private func stopChatStatusSparkleAnimation() {
-        chatStatusIcon.layer?.removeAnimation(forKey: Self.chatStatusSparklePulseKey)
-        chatStatusIcon.layer?.transform = CATransform3DIdentity
-    }
-
     private func syncWelcomeSubtitleBreathingAnimation() {
         guard !prefersReducedMotion else {
             stopWelcomeSubtitleBreathingAnimation()
@@ -1520,10 +1305,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         }
         if home {
             syncWelcomeSubtitleBreathingAnimation()
-            syncChatStatusSparkleAnimation()
         } else {
             stopWelcomeSubtitleBreathingAnimation()
-            stopChatStatusSparkleAnimation()
         }
     }
 
@@ -1590,7 +1373,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
 
     private func startJobSearchRequest(effectiveQuery: String, isContinuation: Bool) {
         isAwaitingResponse = true
-        setChatStatusLabel(Self.chatStatusLoadingMessage)
         addInlineChatThinkingRow()
         setInputEnabled(false)
         let contextMessages = chatMessages
@@ -1620,14 +1402,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
                     )
                     self.chatMessages.append(ChatMessage(role: "assistant", content: reply))
                     self.appendChatBubble(text: reply, isUser: false, jobs: freshJobs)
-                    self.setChatStatusLabel(reply)
                 case .failure(let error):
                     self.appendChatBubble(text: error.localizedDescription, isUser: false)
-                    if error is URLError {
-                        self.setChatStatusLabel("Could not reach API. Try again.")
-                    } else {
-                        self.setChatStatusLabel("Search did not finish. Try again.")
-                    }
                 }
             }
         }
@@ -1733,9 +1509,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
 
     func controlTextDidBeginEditing(_ obj: Notification) {
         applySearchFieldInsertionPoint(obj.object)
-        if (obj.object as? NSTextField) === jobKeywordsField {
-            setChatStatusLabel("Opening the vault...")
-        }
     }
 
     func controlTextDidChange(_ obj: Notification) {
@@ -1770,7 +1543,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         let welcome = "Tell me what role you want and I will return job descriptions, key skills, and a quick fit summary."
         chatMessages.append(ChatMessage(role: "assistant", content: welcome))
         appendChatBubble(text: welcome, isUser: false)
-        setChatStatusLabel("Ask me to find jobs")
     }
 
     private func appendChatBubble(text: String, isUser: Bool, jobs: [JobListing]? = nil) {