Просмотр исходного кода

Add Premium upgrade card to sidebar and trim dashboard model

Introduce a bordered sidebar card with gold accent, sparkles label,
headline, supporting copy, and pill-shaped Upgrade to Pro CTA that
opens the default browser. Remove unused greetingName from
DashboardData and the mock provider so the model matches the view.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 недель назад: 3
Родитель
Сommit
3a14a46687

+ 0 - 2
App for Indeed/Models/DashboardModels.swift

@@ -12,7 +12,6 @@ struct SidebarItem {
12 12
 }
13 13
 
14 14
 struct DashboardData {
15
-    let greetingName: String
16 15
     let subtitle: String
17 16
     let sidebarItems: [SidebarItem]
18 17
     let profileInsightsTitle: String
@@ -26,7 +25,6 @@ protocol DashboardDataProviding {
26 25
 final class MockDashboardDataProvider: DashboardDataProviding {
27 26
     func loadDashboardData() -> DashboardData {
28 27
         DashboardData(
29
-            greetingName: "Olivia",
30 28
             subtitle: "Find your perfect job with the power of AI.",
31 29
             sidebarItems: [
32 30
                 SidebarItem(title: "Overview", systemImage: "house.fill", badge: nil),

+ 95 - 1
App for Indeed/Views/DashboardView.swift

@@ -17,6 +17,11 @@ final class DashboardView: NSView {
17 17
         static let primaryText = NSColor(calibratedWhite: 0.96, alpha: 1)
18 18
         static let secondaryText = NSColor(calibratedWhite: 0.62, alpha: 1)
19 19
         static let tertiaryText = NSColor(calibratedWhite: 0.48, alpha: 1)
20
+        static let proCardFill = NSColor(calibratedRed: 0.1, green: 0.09, blue: 0.12, alpha: 1)
21
+        static let proCardBorder = NSColor(calibratedWhite: 1, alpha: 0.09)
22
+        static let proAccent = NSColor(calibratedRed: 0.98, green: 0.82, blue: 0.38, alpha: 1)
23
+        static let proCTABackground = NSColor(calibratedWhite: 0.97, alpha: 1)
24
+        static let proCTAText = NSColor(calibratedWhite: 0.05, alpha: 1)
20 25
     }
21 26
 
22 27
     private let contentStack = NSStackView()
@@ -52,7 +57,7 @@ final class DashboardView: NSView {
52 57
     }
53 58
 
54 59
     func render(_ data: DashboardData) {
55
-        greetingLabel.stringValue = "Welcome back, \(data.greetingName)! 👋"
60
+        greetingLabel.stringValue = "Welcome"
56 61
         subtitleLabel.stringValue = data.subtitle
57 62
         insightsTitleLabel.stringValue = data.profileInsightsTitle
58 63
         insightsBodyLabel.stringValue = data.profileInsightsBody
@@ -321,6 +326,95 @@ final class DashboardView: NSView {
321 326
         sidebarBottomSpacer.setContentHuggingPriority(.defaultLow, for: .vertical)
322 327
         sidebarBottomSpacer.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
323 328
         sidebar.addArrangedSubview(sidebarBottomSpacer)
329
+
330
+        let upgradeCard = NSView()
331
+        upgradeCard.translatesAutoresizingMaskIntoConstraints = false
332
+        upgradeCard.wantsLayer = true
333
+        upgradeCard.layer?.backgroundColor = Theme.proCardFill.cgColor
334
+        upgradeCard.layer?.cornerRadius = 14
335
+        upgradeCard.layer?.borderWidth = 1
336
+        upgradeCard.layer?.borderColor = Theme.proCardBorder.cgColor
337
+        upgradeCard.layer?.masksToBounds = true
338
+
339
+        let accentBar = NSView()
340
+        accentBar.translatesAutoresizingMaskIntoConstraints = false
341
+        accentBar.wantsLayer = true
342
+        accentBar.layer?.backgroundColor = Theme.proAccent.cgColor
343
+
344
+        let inner = NSStackView()
345
+        inner.translatesAutoresizingMaskIntoConstraints = false
346
+        inner.orientation = .vertical
347
+        inner.spacing = 10
348
+        inner.alignment = .leading
349
+
350
+        let proIcon = NSImageView()
351
+        proIcon.translatesAutoresizingMaskIntoConstraints = false
352
+        proIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 13, weight: .semibold)
353
+        proIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: nil)
354
+        proIcon.contentTintColor = Theme.proAccent
355
+
356
+        let proEyebrow = NSTextField(labelWithString: "Premium")
357
+        proEyebrow.font = .systemFont(ofSize: 11, weight: .heavy)
358
+        proEyebrow.textColor = Theme.proAccent
359
+        proEyebrow.alignment = .left
360
+
361
+        let eyebrowRow = NSStackView(views: [proIcon, proEyebrow])
362
+        eyebrowRow.orientation = .horizontal
363
+        eyebrowRow.spacing = 6
364
+        eyebrowRow.alignment = .centerY
365
+
366
+        let headline = NSTextField(labelWithString: "Upgrade to Pro")
367
+        headline.font = .systemFont(ofSize: 16, weight: .bold)
368
+        headline.textColor = Theme.primaryText
369
+        headline.alignment = .left
370
+
371
+        let upgradeDescription = NSTextField(wrappingLabelWithString: "Unlimited AI matches, smart alerts, and interview prep—all in one place.")
372
+        upgradeDescription.font = .systemFont(ofSize: 12, weight: .regular)
373
+        upgradeDescription.textColor = Theme.secondaryText
374
+        upgradeDescription.preferredMaxLayoutWidth = 165
375
+
376
+        let upgradeButton = NSButton(title: "Upgrade to Pro", target: self, action: #selector(didTapUpgradeToPro))
377
+        upgradeButton.isBordered = false
378
+        upgradeButton.bezelStyle = .rounded
379
+        upgradeButton.font = .systemFont(ofSize: 13, weight: .bold)
380
+        upgradeButton.contentTintColor = Theme.proCTAText
381
+        upgradeButton.wantsLayer = true
382
+        upgradeButton.layer?.backgroundColor = Theme.proCTABackground.cgColor
383
+        upgradeButton.layer?.cornerRadius = 20
384
+        upgradeButton.translatesAutoresizingMaskIntoConstraints = false
385
+        upgradeButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
386
+
387
+        inner.addArrangedSubview(eyebrowRow)
388
+        inner.addArrangedSubview(headline)
389
+        inner.addArrangedSubview(upgradeDescription)
390
+        inner.addArrangedSubview(upgradeButton)
391
+
392
+        upgradeCard.addSubview(accentBar)
393
+        upgradeCard.addSubview(inner)
394
+
395
+        let cardWidth: CGFloat = 197
396
+        NSLayoutConstraint.activate([
397
+            upgradeCard.widthAnchor.constraint(equalToConstant: cardWidth),
398
+
399
+            accentBar.topAnchor.constraint(equalTo: upgradeCard.topAnchor),
400
+            accentBar.leadingAnchor.constraint(equalTo: upgradeCard.leadingAnchor),
401
+            accentBar.trailingAnchor.constraint(equalTo: upgradeCard.trailingAnchor),
402
+            accentBar.heightAnchor.constraint(equalToConstant: 2),
403
+
404
+            inner.leadingAnchor.constraint(equalTo: upgradeCard.leadingAnchor, constant: 14),
405
+            inner.trailingAnchor.constraint(equalTo: upgradeCard.trailingAnchor, constant: -14),
406
+            inner.topAnchor.constraint(equalTo: accentBar.bottomAnchor, constant: 12),
407
+            inner.bottomAnchor.constraint(equalTo: upgradeCard.bottomAnchor, constant: -14),
408
+
409
+            upgradeButton.widthAnchor.constraint(equalTo: inner.widthAnchor)
410
+        ])
411
+
412
+        sidebar.addArrangedSubview(upgradeCard)
413
+    }
414
+
415
+    @objc private func didTapUpgradeToPro() {
416
+        guard let url = URL(string: "https://www.indeed.com") else { return }
417
+        NSWorkspace.shared.open(url)
324 418
     }
325 419
 
326 420
     private func updateDocumentLayout() {