Jelajahi Sumber

Fix dashboard scroll: only job list uses NSScrollView

Remove the full-window scroll view so the chrome, welcome block, and
search bar stay fixed. Wrap job cards in a dedicated vertical
NSScrollView with document layout tied to the clip view.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 2 bulan lalu
induk
melakukan
6b4c5b3f4e
1 mengubah file dengan 21 tambahan dan 35 penghapusan
  1. 21 35
      App for Indeed/Views/DashboardView.swift

+ 21 - 35
App for Indeed/Views/DashboardView.swift

@@ -35,7 +35,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
     }
 
     private let contentStack = NSStackView()
-    private let documentContainer = NSView()
     private let chromeContainer = NSView()
     private let sidebar = NSStackView()
     private let mainHost = NSView()
@@ -50,7 +49,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
     private let findJobsCTAHost = NSView()
     private let findJobsCTAChrome = NSView()
     private var findJobsCTAGradientLayer: CAGradientLayer?
-    private let scrollView = NSScrollView()
+    private let jobListingsScrollView = NSScrollView()
     private let jobListingsContainer = NSView()
     private let jobListingsStack = NSStackView()
 
@@ -69,7 +68,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
 
     override func layout() {
         super.layout()
-        updateDocumentLayout()
         updateSearchBarShadowPath()
         findJobsCTAGradientLayer?.frame = findJobsCTAChrome.bounds
         updateFindJobsCTAShadowPath()
@@ -85,18 +83,12 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         }
         configureSidebar()
         configureJobListings(data.jobListings)
-        updateDocumentLayout()
     }
 
     private func setupLayout() {
         wantsLayer = true
         layer?.backgroundColor = Theme.pageBackground.cgColor
 
-        scrollView.translatesAutoresizingMaskIntoConstraints = false
-        scrollView.hasVerticalScroller = true
-        scrollView.drawsBackground = false
-        addSubview(scrollView)
-
         contentStack.orientation = .horizontal
         contentStack.spacing = 20
         contentStack.distribution = .fill
@@ -104,16 +96,12 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         contentStack.alignment = .height
         contentStack.edgeInsets = NSEdgeInsets(top: 24, left: 24, bottom: 24, right: 24)
 
-        documentContainer.translatesAutoresizingMaskIntoConstraints = true
-        documentContainer.autoresizingMask = [.width]
-        documentContainer.frame = NSRect(x: 0, y: 0, width: 1040, height: 900)
         chromeContainer.translatesAutoresizingMaskIntoConstraints = false
         chromeContainer.wantsLayer = true
         chromeContainer.layer?.backgroundColor = Theme.chromeBackground.cgColor
         chromeContainer.layer?.cornerRadius = 0
-        documentContainer.addSubview(chromeContainer)
+        addSubview(chromeContainer)
         chromeContainer.addSubview(contentStack)
-        scrollView.documentView = documentContainer
 
         sidebar.orientation = .vertical
         sidebar.spacing = 10
@@ -188,32 +176,31 @@ final class DashboardView: NSView, NSTextFieldDelegate {
             jobListingsStack.bottomAnchor.constraint(equalTo: jobListingsContainer.bottomAnchor)
         ])
 
-        let overlayBottomSpacer = NSView()
-        overlayBottomSpacer.translatesAutoresizingMaskIntoConstraints = false
-        overlayBottomSpacer.setContentHuggingPriority(.defaultLow, for: .vertical)
-        overlayBottomSpacer.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
+        jobListingsScrollView.translatesAutoresizingMaskIntoConstraints = false
+        jobListingsScrollView.hasVerticalScroller = true
+        jobListingsScrollView.hasHorizontalScroller = false
+        jobListingsScrollView.autohidesScrollers = true
+        jobListingsScrollView.drawsBackground = false
+        jobListingsScrollView.borderType = .noBorder
+        jobListingsScrollView.documentView = jobListingsContainer
+        jobListingsScrollView.setContentHuggingPriority(.defaultLow, for: .vertical)
+        jobListingsScrollView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
 
         mainOverlay.addArrangedSubview(topInset)
         mainOverlay.addArrangedSubview(titleBlock)
         mainOverlay.addArrangedSubview(midSpacer)
         mainOverlay.addArrangedSubview(searchBarShadowHost)
         mainOverlay.addArrangedSubview(listingsTopSpacer)
-        mainOverlay.addArrangedSubview(jobListingsContainer)
-        mainOverlay.addArrangedSubview(overlayBottomSpacer)
+        mainOverlay.addArrangedSubview(jobListingsScrollView)
 
         contentStack.addArrangedSubview(sidebar)
         contentStack.addArrangedSubview(mainHost)
 
         NSLayoutConstraint.activate([
-            scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
-            scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
-            scrollView.topAnchor.constraint(equalTo: topAnchor),
-            scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
-
-            chromeContainer.leadingAnchor.constraint(equalTo: documentContainer.leadingAnchor),
-            chromeContainer.trailingAnchor.constraint(equalTo: documentContainer.trailingAnchor),
-            chromeContainer.topAnchor.constraint(equalTo: documentContainer.topAnchor),
-            chromeContainer.bottomAnchor.constraint(equalTo: documentContainer.bottomAnchor),
+            chromeContainer.leadingAnchor.constraint(equalTo: leadingAnchor),
+            chromeContainer.trailingAnchor.constraint(equalTo: trailingAnchor),
+            chromeContainer.topAnchor.constraint(equalTo: topAnchor),
+            chromeContainer.bottomAnchor.constraint(equalTo: bottomAnchor),
 
             contentStack.leadingAnchor.constraint(equalTo: chromeContainer.leadingAnchor),
             contentStack.trailingAnchor.constraint(equalTo: chromeContainer.trailingAnchor),
@@ -229,7 +216,11 @@ final class DashboardView: NSView, NSTextFieldDelegate {
             mainOverlay.bottomAnchor.constraint(equalTo: mainHost.bottomAnchor, constant: -24),
 
             searchBarShadowHost.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
-            jobListingsContainer.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
+            jobListingsScrollView.widthAnchor.constraint(equalTo: mainOverlay.widthAnchor, multiplier: 0.92),
+
+            jobListingsContainer.topAnchor.constraint(equalTo: jobListingsScrollView.contentView.topAnchor),
+            jobListingsContainer.leadingAnchor.constraint(equalTo: jobListingsScrollView.contentView.leadingAnchor),
+            jobListingsContainer.widthAnchor.constraint(equalTo: jobListingsScrollView.contentView.widthAnchor),
 
             greetingLabel.leadingAnchor.constraint(equalTo: mainOverlay.leadingAnchor, constant: 24),
             greetingLabel.trailingAnchor.constraint(equalTo: mainOverlay.trailingAnchor, constant: -24),
@@ -699,11 +690,6 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         configureSidebar()
     }
 
-    private func updateDocumentLayout() {
-        documentContainer.layoutSubtreeIfNeeded()
-        let fittingHeight = max(chromeContainer.fittingSize.height, bounds.height)
-        documentContainer.frame = NSRect(x: 0, y: 0, width: bounds.width, height: fittingHeight)
-    }
 }
 
 /// Captures clicks for the full sidebar pill so icon, label, and padding behave as one tab.