Procházet zdrojové kódy

Replace insights card with wide search bar on dashboard.

Remove profile insights fields from DashboardData. Add a centered search field with icon and placeholder; width follows the main overlay at 82% instead of a fixed width.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 před 3 týdny
rodič
revize
528d160db1

+ 1 - 5
App for Indeed/Models/DashboardModels.swift

@@ -14,8 +14,6 @@ struct SidebarItem {
14 14
 struct DashboardData {
15 15
     let subtitle: String
16 16
     let sidebarItems: [SidebarItem]
17
-    let profileInsightsTitle: String
18
-    let profileInsightsBody: String
19 17
 }
20 18
 
21 19
 protocol DashboardDataProviding {
@@ -32,9 +30,7 @@ final class MockDashboardDataProvider: DashboardDataProviding {
32 30
                 SidebarItem(title: "Interviews", systemImage: "list.bullet", badge: nil),
33 31
                 SidebarItem(title: "Profile", systemImage: "person", badge: nil),
34 32
                 SidebarItem(title: "Settings", systemImage: "gearshape", badge: nil)
35
-            ],
36
-            profileInsightsTitle: "AI insights",
37
-            profileInsightsBody: "Saved jobs and interviews at a glance."
33
+            ]
38 34
         )
39 35
     }
40 36
 }

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

@@ -32,12 +32,9 @@ final class DashboardView: NSView {
32 32
     private let mainOverlay = NSStackView()
33 33
     private let greetingLabel = NSTextField(labelWithString: "")
34 34
     private let subtitleLabel = NSTextField(labelWithString: "")
35
-    private let insightsCard = NSView()
36
-    private let insightsTitleLabel = NSTextField(labelWithString: "")
37
-    private let insightsBodyLabel = NSTextField(labelWithString: "")
38
-    private let togglesLabel = NSTextField(labelWithString: "Show:")
39
-    private let savedToggleButton = NSButton(title: "Saved", target: nil, action: nil)
40
-    private let interviewsToggleButton = NSButton(title: "Interviews", target: nil, action: nil)
35
+    private let searchCard = NSView()
36
+    private let searchIcon = NSImageView()
37
+    private let searchField = NSTextField()
41 38
     private let sparkleView = NSImageView()
42 39
     private let scrollView = NSScrollView()
43 40
 
@@ -59,8 +56,6 @@ final class DashboardView: NSView {
59 56
     func render(_ data: DashboardData) {
60 57
         greetingLabel.stringValue = "Welcome"
61 58
         subtitleLabel.stringValue = data.subtitle
62
-        insightsTitleLabel.stringValue = data.profileInsightsTitle
63
-        insightsBodyLabel.stringValue = data.profileInsightsBody
64 59
         configureSidebar(data.sidebarItems)
65 60
         updateDocumentLayout()
66 61
     }
@@ -130,7 +125,7 @@ final class DashboardView: NSView {
130 125
         topInset.translatesAutoresizingMaskIntoConstraints = false
131 126
         topInset.heightAnchor.constraint(equalToConstant: 32).isActive = true
132 127
 
133
-        configureInsightsCard()
128
+        configureSearchCard()
134 129
 
135 130
         let titleBlock = NSStackView(views: [greetingLabel, subtitleLabel])
136 131
         titleBlock.orientation = .vertical
@@ -149,7 +144,7 @@ final class DashboardView: NSView {
149 144
         mainOverlay.addArrangedSubview(topInset)
150 145
         mainOverlay.addArrangedSubview(titleBlock)
151 146
         mainOverlay.addArrangedSubview(midSpacer)
152
-        mainOverlay.addArrangedSubview(insightsCard)
147
+        mainOverlay.addArrangedSubview(searchCard)
153 148
         mainOverlay.addArrangedSubview(overlayBottomSpacer)
154 149
 
155 150
         sparkleView.translatesAutoresizingMaskIntoConstraints = false
@@ -185,6 +180,8 @@ final class DashboardView: NSView {
185 180
             mainOverlay.topAnchor.constraint(equalTo: mainHost.topAnchor),
186 181
             mainOverlay.bottomAnchor.constraint(equalTo: mainHost.bottomAnchor, constant: -24),
187 182
 
183
+            searchCard.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.82),
184
+
188 185
             greetingLabel.leadingAnchor.constraint(equalTo: mainOverlay.leadingAnchor, constant: 24),
189 186
             greetingLabel.trailingAnchor.constraint(equalTo: mainOverlay.trailingAnchor, constant: -24),
190 187
             subtitleLabel.leadingAnchor.constraint(equalTo: greetingLabel.leadingAnchor),
@@ -195,70 +192,58 @@ final class DashboardView: NSView {
195 192
         ])
196 193
     }
197 194
 
198
-    private func configureInsightsCard() {
199
-        insightsCard.wantsLayer = true
200
-        insightsCard.layer?.backgroundColor = Theme.cardBackground.cgColor
201
-        insightsCard.layer?.cornerRadius = 18
202
-        insightsCard.translatesAutoresizingMaskIntoConstraints = false
203
-
204
-        insightsTitleLabel.font = .systemFont(ofSize: 20, weight: .semibold)
205
-        insightsTitleLabel.textColor = Theme.primaryText
206
-        insightsTitleLabel.alignment = .center
207
-        insightsTitleLabel.maximumNumberOfLines = 1
208
-
209
-        insightsBodyLabel.font = .systemFont(ofSize: 13, weight: .regular)
210
-        insightsBodyLabel.textColor = Theme.secondaryText
211
-        insightsBodyLabel.alignment = .center
212
-        insightsBodyLabel.maximumNumberOfLines = 4
213
-        insightsBodyLabel.lineBreakMode = .byWordWrapping
214
-        insightsBodyLabel.preferredMaxLayoutWidth = 400
215
-
216
-        togglesLabel.font = .systemFont(ofSize: 12, weight: .medium)
217
-        togglesLabel.textColor = Theme.tertiaryText
218
-        togglesLabel.alignment = .center
219
-        togglesLabel.maximumNumberOfLines = 1
220
-
221
-        styleToggle(savedToggleButton)
222
-        styleToggle(interviewsToggleButton)
223
-
224
-        let toggleRow = NSStackView(views: [savedToggleButton, interviewsToggleButton])
225
-        toggleRow.orientation = .horizontal
226
-        toggleRow.spacing = 10
227
-        toggleRow.alignment = .centerY
228
-
229
-        let inner = NSStackView(views: [
230
-            insightsTitleLabel,
231
-            insightsBodyLabel,
232
-            togglesLabel,
233
-            toggleRow
234
-        ])
235
-        inner.orientation = .vertical
236
-        inner.spacing = 10
237
-        inner.alignment = .centerX
238
-        inner.distribution = .fill
239
-        inner.translatesAutoresizingMaskIntoConstraints = false
195
+    private func configureSearchCard() {
196
+        searchCard.wantsLayer = true
197
+        searchCard.layer?.backgroundColor = Theme.cardBackground.cgColor
198
+        searchCard.layer?.cornerRadius = 14
199
+        searchCard.layer?.borderWidth = 1
200
+        searchCard.layer?.borderColor = NSColor(calibratedWhite: 1, alpha: 0.06).cgColor
201
+        searchCard.translatesAutoresizingMaskIntoConstraints = false
202
+        searchCard.setContentHuggingPriority(.defaultHigh, for: .vertical)
203
+
204
+        searchIcon.translatesAutoresizingMaskIntoConstraints = false
205
+        searchIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 15, weight: .medium)
206
+        searchIcon.image = NSImage(systemSymbolName: "magnifyingglass", accessibilityDescription: "Search")
207
+        searchIcon.contentTintColor = Theme.secondaryText
208
+
209
+        searchField.translatesAutoresizingMaskIntoConstraints = false
210
+        searchField.isBordered = false
211
+        searchField.drawsBackground = false
212
+        searchField.focusRingType = .none
213
+        searchField.font = .systemFont(ofSize: 14, weight: .regular)
214
+        searchField.textColor = Theme.primaryText
215
+        searchField.placeholderAttributedString = NSAttributedString(
216
+            string: "Search jobs, companies, or locations",
217
+            attributes: [
218
+                .foregroundColor: Theme.tertiaryText,
219
+                .font: NSFont.systemFont(ofSize: 14, weight: .regular)
220
+            ]
221
+        )
222
+        searchField.cell?.usesSingleLineMode = true
223
+        searchField.cell?.wraps = false
224
+        searchField.cell?.isScrollable = true
225
+        searchField.target = self
226
+        searchField.action = #selector(didSubmitSearch)
227
+
228
+        searchCard.addSubview(searchIcon)
229
+        searchCard.addSubview(searchField)
240 230
 
241
-        insightsCard.setContentHuggingPriority(.defaultHigh, for: .vertical)
242
-        insightsCard.addSubview(inner)
243 231
         NSLayoutConstraint.activate([
244
-            inner.leadingAnchor.constraint(equalTo: insightsCard.leadingAnchor, constant: 32),
245
-            inner.trailingAnchor.constraint(equalTo: insightsCard.trailingAnchor, constant: -32),
246
-            inner.topAnchor.constraint(equalTo: insightsCard.topAnchor, constant: 22),
247
-            inner.bottomAnchor.constraint(equalTo: insightsCard.bottomAnchor, constant: -22),
248
-            insightsCard.widthAnchor.constraint(equalToConstant: 440)
232
+            searchCard.heightAnchor.constraint(equalToConstant: 48),
233
+
234
+            searchIcon.leadingAnchor.constraint(equalTo: searchCard.leadingAnchor, constant: 16),
235
+            searchIcon.centerYAnchor.constraint(equalTo: searchCard.centerYAnchor),
236
+            searchIcon.widthAnchor.constraint(equalToConstant: 18),
237
+            searchIcon.heightAnchor.constraint(equalToConstant: 18),
238
+
239
+            searchField.leadingAnchor.constraint(equalTo: searchIcon.trailingAnchor, constant: 10),
240
+            searchField.trailingAnchor.constraint(equalTo: searchCard.trailingAnchor, constant: -16),
241
+            searchField.centerYAnchor.constraint(equalTo: searchCard.centerYAnchor)
249 242
         ])
250 243
     }
251 244
 
252
-    private func styleToggle(_ button: NSButton) {
253
-        button.bezelStyle = .rounded
254
-        button.font = .systemFont(ofSize: 12, weight: .medium)
255
-        button.contentTintColor = Theme.secondaryText
256
-        button.wantsLayer = true
257
-        button.layer?.backgroundColor = Theme.toggleBackground.cgColor
258
-        button.layer?.cornerRadius = 8
259
-        button.translatesAutoresizingMaskIntoConstraints = false
260
-        button.widthAnchor.constraint(equalToConstant: 108).isActive = true
261
-        button.heightAnchor.constraint(equalToConstant: 30).isActive = true
245
+    @objc private func didSubmitSearch() {
246
+        // Hook up search submission here when wiring up real data.
262 247
     }
263 248
 
264 249
     private func configureSidebar(_ items: [SidebarItem]) {