Procházet zdrojové kódy

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 před 1 týdnem
rodič
revize
d55817f09f
1 změnil soubory, kde provedl 61 přidání a 10 odebrání
  1. 61 10
      classroom_app/ViewController.swift

+ 61 - 10
classroom_app/ViewController.swift

@@ -5530,9 +5530,30 @@ private final class EnrolledClassDetailsViewController: NSViewController {
5530
         subtitle.font = NSFont.systemFont(ofSize: 12, weight: .medium)
5530
         subtitle.font = NSFont.systemFont(ofSize: 12, weight: .medium)
5531
         subtitle.textColor = palette.textMuted
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
         let left = NSStackView(views: [title, subtitle])
5558
         let left = NSStackView(views: [title, subtitle])
5538
         left.orientation = .vertical
5559
         left.orientation = .vertical
@@ -5726,13 +5747,22 @@ private final class EnrolledClassDetailsViewController: NSViewController {
5726
     }
5747
     }
5727
 
5748
 
5728
     private func makeAttachmentPreview(_ attachment: ClassroomAttachment) -> NSView {
5749
     private func makeAttachmentPreview(_ attachment: ClassroomAttachment) -> NSView {
5729
-        let preview = NSView()
5750
+        let preview = HoverTrackingView()
5730
         preview.translatesAutoresizingMaskIntoConstraints = false
5751
         preview.translatesAutoresizingMaskIntoConstraints = false
5731
         preview.wantsLayer = true
5752
         preview.wantsLayer = true
5753
+        preview.showsHandCursor = false
5732
         preview.layer?.cornerRadius = 12
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
         preview.layer?.borderWidth = 1
5758
         preview.layer?.borderWidth = 1
5735
         preview.layer?.borderColor = palette.inputBorder.cgColor
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
         let titleButton = NSButton(title: attachment.title, target: self, action: #selector(downloadPressed(_:)))
5767
         let titleButton = NSButton(title: attachment.title, target: self, action: #selector(downloadPressed(_:)))
5738
         titleButton.translatesAutoresizingMaskIntoConstraints = false
5768
         titleButton.translatesAutoresizingMaskIntoConstraints = false
@@ -5775,23 +5805,44 @@ private final class EnrolledClassDetailsViewController: NSViewController {
5775
     }
5805
     }
5776
 
5806
 
5777
     private func makeInlineActionButton(title: String, url: URL) -> NSButton {
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
         open.bezelStyle = .inline
5810
         open.bezelStyle = .inline
5780
         open.identifier = NSUserInterfaceItemIdentifier(url.absoluteString)
5811
         open.identifier = NSUserInterfaceItemIdentifier(url.absoluteString)
5781
         open.font = NSFont.systemFont(ofSize: 12, weight: .semibold)
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
         return open
5824
         return open
5783
     }
5825
     }
5784
 
5826
 
5785
     private func makeStreamCardShell() -> NSView {
5827
     private func makeStreamCardShell() -> NSView {
5786
-        let card = NSView()
5828
+        let card = HoverTrackingView()
5787
         card.translatesAutoresizingMaskIntoConstraints = false
5829
         card.translatesAutoresizingMaskIntoConstraints = false
5788
         card.wantsLayer = true
5830
         card.wantsLayer = true
5831
+        card.showsHandCursor = false
5789
         card.layer?.cornerRadius = 10
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
         card.layer?.borderWidth = 1
5838
         card.layer?.borderWidth = 1
5794
         card.layer?.borderColor = palette.inputBorder.cgColor
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
         return card
5846
         return card
5796
     }
5847
     }
5797
 
5848