Bladeren bron

Polish popup interactions with theme-matched hover states.

Add subtle hover feedback to stream cards, attachment previews, action links, and replace the header open action with a professional icon button that matches the app's visual language.

Made-with: Cursor
huzaifahayat12 1 week geleden
bovenliggende
commit
d55817f09f
1 gewijzigde bestanden met toevoegingen van 61 en 10 verwijderingen
  1. 61 10
      classroom_app/ViewController.swift

+ 61 - 10
classroom_app/ViewController.swift

@@ -5530,9 +5530,30 @@ private final class EnrolledClassDetailsViewController: NSViewController {
5530 5530
         subtitle.font = NSFont.systemFont(ofSize: 12, weight: .medium)
5531 5531
         subtitle.textColor = palette.textMuted
5532 5532
 
5533
-        let openClassButton = NSButton(title: "Open in Classroom", target: self, action: #selector(openClassPressed(_:)))
5534
-        openClassButton.bezelStyle = .rounded
5535
-        openClassButton.font = NSFont.systemFont(ofSize: 12, weight: .semibold)
5533
+        let openClassButton = HoverButton(title: "", target: self, action: #selector(openClassPressed(_:)))
5534
+        openClassButton.translatesAutoresizingMaskIntoConstraints = false
5535
+        openClassButton.bezelStyle = .regularSquare
5536
+        openClassButton.image = NSImage(systemSymbolName: "arrow.up.right.square", accessibilityDescription: "Open in Classroom")
5537
+        openClassButton.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 14, weight: .semibold)
5538
+        openClassButton.imagePosition = .imageOnly
5539
+        openClassButton.contentTintColor = palette.textPrimary
5540
+        openClassButton.setAccessibilityLabel("Open in Classroom")
5541
+        openClassButton.toolTip = "Open in Classroom"
5542
+        openClassButton.wantsLayer = true
5543
+        openClassButton.layer?.cornerRadius = 8
5544
+        openClassButton.layer?.borderWidth = 1
5545
+        openClassButton.widthAnchor.constraint(equalToConstant: 34).isActive = true
5546
+        openClassButton.heightAnchor.constraint(equalToConstant: 34).isActive = true
5547
+        let buttonBase = palette.inputBackground
5548
+        let buttonHover = buttonBase.blended(withFraction: 0.14, of: palette.primaryBlue) ?? buttonBase
5549
+        openClassButton.layer?.backgroundColor = buttonBase.cgColor
5550
+        openClassButton.layer?.borderColor = palette.inputBorder.cgColor
5551
+        openClassButton.onHoverChanged = { [weak openClassButton] hovering in
5552
+            guard let openClassButton else { return }
5553
+            openClassButton.layer?.backgroundColor = (hovering ? buttonHover : buttonBase).cgColor
5554
+            openClassButton.layer?.borderColor = (hovering ? self.palette.primaryBlueBorder : self.palette.inputBorder).cgColor
5555
+        }
5556
+        openClassButton.onHoverChanged?(false)
5536 5557
 
5537 5558
         let left = NSStackView(views: [title, subtitle])
5538 5559
         left.orientation = .vertical
@@ -5726,13 +5747,22 @@ private final class EnrolledClassDetailsViewController: NSViewController {
5726 5747
     }
5727 5748
 
5728 5749
     private func makeAttachmentPreview(_ attachment: ClassroomAttachment) -> NSView {
5729
-        let preview = NSView()
5750
+        let preview = HoverTrackingView()
5730 5751
         preview.translatesAutoresizingMaskIntoConstraints = false
5731 5752
         preview.wantsLayer = true
5753
+        preview.showsHandCursor = false
5732 5754
         preview.layer?.cornerRadius = 12
5733
-        preview.layer?.backgroundColor = palette.sectionCard.cgColor
5755
+        let previewBase = palette.sectionCard
5756
+        let previewHover = previewBase.blended(withFraction: 0.14, of: palette.primaryBlue) ?? previewBase
5757
+        preview.layer?.backgroundColor = previewBase.cgColor
5734 5758
         preview.layer?.borderWidth = 1
5735 5759
         preview.layer?.borderColor = palette.inputBorder.cgColor
5760
+        preview.onHoverChanged = { [weak preview] hovering in
5761
+            guard let preview else { return }
5762
+            preview.layer?.backgroundColor = (hovering ? previewHover : previewBase).cgColor
5763
+            preview.layer?.borderColor = (hovering ? self.palette.primaryBlueBorder : self.palette.inputBorder).cgColor
5764
+        }
5765
+        preview.onHoverChanged?(false)
5736 5766
 
5737 5767
         let titleButton = NSButton(title: attachment.title, target: self, action: #selector(downloadPressed(_:)))
5738 5768
         titleButton.translatesAutoresizingMaskIntoConstraints = false
@@ -5775,23 +5805,44 @@ private final class EnrolledClassDetailsViewController: NSViewController {
5775 5805
     }
5776 5806
 
5777 5807
     private func makeInlineActionButton(title: String, url: URL) -> NSButton {
5778
-        let open = NSButton(title: title, target: self, action: #selector(openLinkPressed(_:)))
5808
+        let open = HoverButton(title: title, target: self, action: #selector(openLinkPressed(_:)))
5809
+        open.translatesAutoresizingMaskIntoConstraints = false
5779 5810
         open.bezelStyle = .inline
5780 5811
         open.identifier = NSUserInterfaceItemIdentifier(url.absoluteString)
5781 5812
         open.font = NSFont.systemFont(ofSize: 12, weight: .semibold)
5813
+        open.wantsLayer = true
5814
+        open.layer?.cornerRadius = 8
5815
+        open.layer?.backgroundColor = NSColor.clear.cgColor
5816
+        open.onHoverChanged = { [weak open] hovering in
5817
+            guard let open else { return }
5818
+            let bg = hovering
5819
+                ? (self.palette.inputBackground.blended(withFraction: 0.18, of: self.palette.primaryBlue) ?? self.palette.inputBackground)
5820
+                : NSColor.clear
5821
+            open.layer?.backgroundColor = bg.cgColor
5822
+        }
5823
+        open.onHoverChanged?(false)
5782 5824
         return open
5783 5825
     }
5784 5826
 
5785 5827
     private func makeStreamCardShell() -> NSView {
5786
-        let card = NSView()
5828
+        let card = HoverTrackingView()
5787 5829
         card.translatesAutoresizingMaskIntoConstraints = false
5788 5830
         card.wantsLayer = true
5831
+        card.showsHandCursor = false
5789 5832
         card.layer?.cornerRadius = 10
5790
-        card.layer?.backgroundColor = palette.inputBackground
5791
-            .blended(withFraction: 0.32, of: palette.sectionCard)?
5792
-            .cgColor ?? palette.inputBackground.cgColor
5833
+        let baseColor = palette.inputBackground
5834
+            .blended(withFraction: 0.32, of: palette.sectionCard)
5835
+            ?? palette.inputBackground
5836
+        let hoverColor = baseColor.blended(withFraction: 0.12, of: palette.primaryBlue) ?? baseColor
5837
+        card.layer?.backgroundColor = baseColor.cgColor
5793 5838
         card.layer?.borderWidth = 1
5794 5839
         card.layer?.borderColor = palette.inputBorder.cgColor
5840
+        card.onHoverChanged = { [weak card] hovering in
5841
+            guard let card else { return }
5842
+            card.layer?.backgroundColor = (hovering ? hoverColor : baseColor).cgColor
5843
+            card.layer?.borderColor = (hovering ? self.palette.primaryBlueBorder : self.palette.inputBorder).cgColor
5844
+        }
5845
+        card.onHoverChanged?(false)
5795 5846
         return card
5796 5847
     }
5797 5848