Parcourir la Source

Refine home top bar: nav cluster, search spacing, Upgrade to Pro

Group back, forward, and history with the search field and center the row;
keep the trailing actions pinned right. Replace the plus, bell, and grid
controls with a pill-shaped Upgrade to Pro button next to the profile chip.

Tune nav control sizes (smaller chevrons, history spacing, gap before search),
use transparent-style glyph buttons with tooltips on Back, Forward, and
History, and remove unused top-bar glyph helpers.

Made-with: Cursor
huzaifahayat12 il y a 5 jours
Parent
commit
ad585b8052
1 fichiers modifiés avec 68 ajouts et 46 suppressions
  1. 68 46
      zoom_app/ViewController.swift

+ 68 - 46
zoom_app/ViewController.swift

@@ -26,8 +26,6 @@ class ViewController: NSViewController {
26
     private let chromeUnifiedBackground = NSColor(calibratedRed: 22 / 255, green: 23 / 255, blue: 26 / 255, alpha: 1)
26
     private let chromeUnifiedBackground = NSColor(calibratedRed: 22 / 255, green: 23 / 255, blue: 26 / 255, alpha: 1)
27
     private let searchPillBackground = NSColor.white.withAlphaComponent(0.06)
27
     private let searchPillBackground = NSColor.white.withAlphaComponent(0.06)
28
     private let meetingCardBackground = NSColor(calibratedRed: 30 / 255, green: 34 / 255, blue: 42 / 255, alpha: 1)
28
     private let meetingCardBackground = NSColor(calibratedRed: 30 / 255, green: 34 / 255, blue: 42 / 255, alpha: 1)
29
-    private let titleBarControlBackground = NSColor.white.withAlphaComponent(0.04)
30
-    private let titleBarLightControlBackground = NSColor.white.withAlphaComponent(0.02)
31
     private let appShellCornerRadius: CGFloat = 20
29
     private let appShellCornerRadius: CGFloat = 20
32
     private let homeChromeHeaderHeight: CGFloat = 56
30
     private let homeChromeHeaderHeight: CGFloat = 56
33
     private let nativeTrafficLightsLeading: CGFloat = 14
31
     private let nativeTrafficLightsLeading: CGFloat = 14
@@ -747,22 +745,35 @@ class ViewController: NSViewController {
747
         searchPill.layer?.cornerRadius = 10
745
         searchPill.layer?.cornerRadius = 10
748
         let search = makeLabel("Search (\u{2318}E)", size: 13, color: mutedText, weight: .regular, centered: true)
746
         let search = makeLabel("Search (\u{2318}E)", size: 13, color: mutedText, weight: .regular, centered: true)
749
         
747
         
748
+        let backForwardCluster = NSStackView()
749
+        backForwardCluster.orientation = .horizontal
750
+        backForwardCluster.spacing = 4
751
+        backForwardCluster.alignment = .centerY
752
+        let backButton = makeNavGlyphButton(symbol: "chevron.left", action: #selector(topBarPlaceholderTapped), dimension: 14, pointSize: 7, toolTip: "Back")
753
+        let forwardButton = makeNavGlyphButton(symbol: "chevron.right", action: #selector(topBarPlaceholderTapped), dimension: 14, pointSize: 7, toolTip: "Forward")
754
+        [backButton, forwardButton].forEach { backForwardCluster.addArrangedSubview($0) }
755
+
750
         let leftTopBarCluster = NSStackView()
756
         let leftTopBarCluster = NSStackView()
751
         leftTopBarCluster.orientation = .horizontal
757
         leftTopBarCluster.orientation = .horizontal
752
-        leftTopBarCluster.spacing = 10
758
+        leftTopBarCluster.spacing = 0
753
         leftTopBarCluster.alignment = .centerY
759
         leftTopBarCluster.alignment = .centerY
754
-        let backButton = makeTopBarGlyphButton(symbol: "chevron.left", action: #selector(topBarPlaceholderTapped))
755
-        let forwardButton = makeTopBarGlyphButton(symbol: "chevron.right", action: #selector(topBarPlaceholderTapped))
756
-        let historyButton = makeTopBarGlyphButton(symbol: "clock.arrow.circlepath", action: #selector(topBarPlaceholderTapped))
757
-        [backButton, forwardButton, historyButton].forEach { leftTopBarCluster.addArrangedSubview($0) }
758
-        
760
+        let historyButton = makeNavGlyphButton(symbol: "clock.arrow.circlepath", action: #selector(topBarPlaceholderTapped), toolTip: "History")
761
+        let navHistoryGap = NSView()
762
+        navHistoryGap.translatesAutoresizingMaskIntoConstraints = false
763
+        navHistoryGap.widthAnchor.constraint(equalToConstant: 12).isActive = true
764
+        [backForwardCluster, navHistoryGap, historyButton].forEach { leftTopBarCluster.addArrangedSubview($0) }
765
+
766
+        let searchRow = NSStackView()
767
+        searchRow.orientation = .horizontal
768
+        searchRow.spacing = 14
769
+        searchRow.alignment = .centerY
770
+        [leftTopBarCluster, searchPill].forEach { searchRow.addArrangedSubview($0) }
771
+
759
         let rightTopBarCluster = NSStackView()
772
         let rightTopBarCluster = NSStackView()
760
         rightTopBarCluster.orientation = .horizontal
773
         rightTopBarCluster.orientation = .horizontal
761
-        rightTopBarCluster.spacing = 8
774
+        rightTopBarCluster.spacing = 10
762
         rightTopBarCluster.alignment = .centerY
775
         rightTopBarCluster.alignment = .centerY
763
-        let plusButton = makeTopBarGlyphButton(symbol: "plus", action: #selector(topBarPlaceholderTapped))
764
-        let notificationButton = makeTopBarGlyphButton(symbol: "bell", action: #selector(topBarPlaceholderTapped))
765
-        let appsButton = makeTopBarIconButton(symbol: "square.grid.2x2", action: #selector(topBarPlaceholderTapped))
776
+        let upgradeToProButton = makeUpgradeToProButton(action: #selector(topBarPlaceholderTapped))
766
 
777
 
767
         let profileChip = NSButton(title: String((profile?.name ?? "H").prefix(1)).uppercased(), target: self, action: #selector(logoutTapped))
778
         let profileChip = NSButton(title: String((profile?.name ?? "H").prefix(1)).uppercased(), target: self, action: #selector(logoutTapped))
768
         profileChip.isBordered = false
779
         profileChip.isBordered = false
@@ -772,7 +783,7 @@ class ViewController: NSViewController {
772
         profileChip.contentTintColor = primaryText
783
         profileChip.contentTintColor = primaryText
773
         profileChip.font = .systemFont(ofSize: 14, weight: .bold)
784
         profileChip.font = .systemFont(ofSize: 14, weight: .bold)
774
         profileChip.toolTip = "Profile (click to logout)"
785
         profileChip.toolTip = "Profile (click to logout)"
775
-        [plusButton, notificationButton, appsButton, profileChip].forEach { rightTopBarCluster.addArrangedSubview($0) }
786
+        [upgradeToProButton, profileChip].forEach { rightTopBarCluster.addArrangedSubview($0) }
776
 
787
 
777
         let welcome = makeLabel("Home", size: 15, color: secondaryText, weight: .medium, centered: false)
788
         let welcome = makeLabel("Home", size: 15, color: secondaryText, weight: .medium, centered: false)
778
         let timeTitle = makeLabel("--:--", size: 56, color: primaryText, weight: .bold, centered: true)
789
         let timeTitle = makeLabel("--:--", size: 56, color: primaryText, weight: .bold, centered: true)
@@ -829,14 +840,13 @@ class ViewController: NSViewController {
829
         content.addSubview(topBarDivider)
840
         content.addSubview(topBarDivider)
830
         content.addSubview(contentColumn)
841
         content.addSubview(contentColumn)
831
 
842
 
832
-        [brandStack, leftTopBarCluster, rightTopBarCluster, searchPill, search].forEach {
843
+        [brandStack, searchRow, backForwardCluster, leftTopBarCluster, rightTopBarCluster, searchPill, search].forEach {
833
             $0.translatesAutoresizingMaskIntoConstraints = false
844
             $0.translatesAutoresizingMaskIntoConstraints = false
834
         }
845
         }
835
         [brandStack].forEach {
846
         [brandStack].forEach {
836
             shell.addSubview($0)
847
             shell.addSubview($0)
837
         }
848
         }
838
-        [leftTopBarCluster, rightTopBarCluster, searchPill, search].forEach {
839
-            $0.translatesAutoresizingMaskIntoConstraints = false
849
+        [searchRow, rightTopBarCluster, search].forEach {
840
             topBar.addSubview($0)
850
             topBar.addSubview($0)
841
         }
851
         }
842
         [welcome, timeTitle, dateTitle, actions, panel, panelHeader, meetingsStatus, noMeeting, meetingsScrollView, openRecordings].forEach {
852
         [welcome, timeTitle, dateTitle, actions, panel, panelHeader, meetingsStatus, noMeeting, meetingsScrollView, openRecordings].forEach {
@@ -850,9 +860,12 @@ class ViewController: NSViewController {
850
         meetingsScrollView.documentView = meetingsDocument
860
         meetingsScrollView.documentView = meetingsDocument
851
         meetingsDocument.addSubview(meetingsStack)
861
         meetingsDocument.addSubview(meetingsStack)
852
 
862
 
863
+        let searchRowCenterX = searchRow.centerXAnchor.constraint(equalTo: topBar.centerXAnchor)
864
+        searchRowCenterX.priority = .defaultHigh
865
+
853
         NSLayoutConstraint.activate([
866
         NSLayoutConstraint.activate([
854
             brandStack.leadingAnchor.constraint(equalTo: shell.leadingAnchor, constant: brandLeadingInset),
867
             brandStack.leadingAnchor.constraint(equalTo: shell.leadingAnchor, constant: brandLeadingInset),
855
-            brandStack.trailingAnchor.constraint(lessThanOrEqualTo: leftTopBarCluster.leadingAnchor, constant: -12),
868
+            brandStack.trailingAnchor.constraint(lessThanOrEqualTo: searchRow.leadingAnchor, constant: -12),
856
             brandStack.centerYAnchor.constraint(equalTo: chromeHeader.centerYAnchor, constant: -1),
869
             brandStack.centerYAnchor.constraint(equalTo: chromeHeader.centerYAnchor, constant: -1),
857
 
870
 
858
             topBar.topAnchor.constraint(equalTo: content.topAnchor),
871
             topBar.topAnchor.constraint(equalTo: content.topAnchor),
@@ -869,18 +882,17 @@ class ViewController: NSViewController {
869
             contentColumn.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 8),
882
             contentColumn.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 8),
870
             contentColumn.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -8),
883
             contentColumn.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -8),
871
 
884
 
872
-            leftTopBarCluster.leadingAnchor.constraint(greaterThanOrEqualTo: topBar.leadingAnchor, constant: 40),
873
-            leftTopBarCluster.leadingAnchor.constraint(greaterThanOrEqualTo: brandStack.trailingAnchor, constant: 16),
874
-            leftTopBarCluster.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
885
+            searchRowCenterX,
886
+            searchRow.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
887
+            searchRow.leadingAnchor.constraint(greaterThanOrEqualTo: topBar.leadingAnchor, constant: 40),
888
+            searchRow.leadingAnchor.constraint(greaterThanOrEqualTo: brandStack.trailingAnchor, constant: 16),
889
+            searchRow.trailingAnchor.constraint(lessThanOrEqualTo: rightTopBarCluster.leadingAnchor, constant: -12),
890
+
875
             rightTopBarCluster.trailingAnchor.constraint(equalTo: topBar.trailingAnchor, constant: -12),
891
             rightTopBarCluster.trailingAnchor.constraint(equalTo: topBar.trailingAnchor, constant: -12),
876
             rightTopBarCluster.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
892
             rightTopBarCluster.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
877
 
893
 
878
-            searchPill.centerXAnchor.constraint(equalTo: topBar.centerXAnchor),
879
-            searchPill.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
880
             searchPill.heightAnchor.constraint(equalToConstant: 32),
894
             searchPill.heightAnchor.constraint(equalToConstant: 32),
881
             searchPill.widthAnchor.constraint(equalToConstant: 320),
895
             searchPill.widthAnchor.constraint(equalToConstant: 320),
882
-            searchPill.leadingAnchor.constraint(greaterThanOrEqualTo: leftTopBarCluster.trailingAnchor, constant: 12),
883
-            searchPill.trailingAnchor.constraint(lessThanOrEqualTo: rightTopBarCluster.leadingAnchor, constant: -12),
884
             search.leadingAnchor.constraint(equalTo: searchPill.leadingAnchor, constant: 12),
896
             search.leadingAnchor.constraint(equalTo: searchPill.leadingAnchor, constant: 12),
885
             search.trailingAnchor.constraint(equalTo: searchPill.trailingAnchor, constant: -12),
897
             search.trailingAnchor.constraint(equalTo: searchPill.trailingAnchor, constant: -12),
886
             search.centerYAnchor.constraint(equalTo: searchPill.centerYAnchor),
898
             search.centerYAnchor.constraint(equalTo: searchPill.centerYAnchor),
@@ -1061,37 +1073,47 @@ class ViewController: NSViewController {
1061
         }
1073
         }
1062
     }
1074
     }
1063
 
1075
 
1064
-    private func makeTopBarIconButton(symbol: String, action: Selector?) -> NSButton {
1065
-        let button = NSButton(title: "", target: action == nil ? nil : self, action: action)
1076
+    private func makeUpgradeToProButton(action: Selector?) -> NSButton {
1077
+        let title = "Upgrade to Pro"
1078
+        let button = NSButton(title: title, target: action == nil ? nil : self, action: action)
1066
         button.isBordered = false
1079
         button.isBordered = false
1080
+        button.focusRingType = .none
1067
         button.wantsLayer = true
1081
         button.wantsLayer = true
1068
-        button.layer?.backgroundColor = titleBarControlBackground.cgColor
1069
-        button.layer?.cornerRadius = 10
1070
-        button.layer?.borderWidth = 1
1071
-        button.layer?.borderColor = NSColor.white.withAlphaComponent(0.05).cgColor
1072
-        button.contentTintColor = secondaryText
1073
-        button.image = NSImage(systemSymbolName: symbol, accessibilityDescription: symbol)
1074
-        button.imageScaling = .scaleProportionallyUpOrDown
1082
+        button.layer?.backgroundColor = accentBlue.cgColor
1083
+        button.layer?.cornerRadius = 17
1084
+        let font = NSFont.systemFont(ofSize: 13, weight: .semibold)
1085
+        button.attributedTitle = NSAttributedString(string: title, attributes: [
1086
+            .foregroundColor: NSColor.white,
1087
+            .font: font
1088
+        ])
1089
+        button.toolTip = title
1075
         button.translatesAutoresizingMaskIntoConstraints = false
1090
         button.translatesAutoresizingMaskIntoConstraints = false
1076
-        button.widthAnchor.constraint(equalToConstant: 30).isActive = true
1077
-        button.heightAnchor.constraint(equalToConstant: 30).isActive = true
1091
+        button.heightAnchor.constraint(equalToConstant: 34).isActive = true
1092
+        button.widthAnchor.constraint(greaterThanOrEqualToConstant: 152).isActive = true
1078
         return button
1093
         return button
1079
     }
1094
     }
1080
-    
1081
-    private func makeTopBarGlyphButton(symbol: String, action: Selector?) -> NSButton {
1095
+
1096
+    /// Back / forward / history: icon-only, no background or border. Back/forward use smaller `dimension` / `pointSize` than history.
1097
+    private func makeNavGlyphButton(symbol: String, action: Selector?, dimension: CGFloat = 18, pointSize: CGFloat = 9, toolTip: String? = nil) -> NSButton {
1082
         let button = NSButton(title: "", target: action == nil ? nil : self, action: action)
1098
         let button = NSButton(title: "", target: action == nil ? nil : self, action: action)
1083
         button.isBordered = false
1099
         button.isBordered = false
1084
-        button.wantsLayer = true
1085
-        button.layer?.backgroundColor = titleBarLightControlBackground.cgColor
1086
-        button.layer?.cornerRadius = 9
1087
-        button.layer?.borderWidth = 1
1088
-        button.layer?.borderColor = NSColor.white.withAlphaComponent(0.03).cgColor
1089
-        button.contentTintColor = secondaryText
1090
-        button.image = NSImage(systemSymbolName: symbol, accessibilityDescription: symbol)
1100
+        button.bezelStyle = .shadowlessSquare
1101
+        button.focusRingType = .none
1102
+        button.contentTintColor = NSColor(calibratedWhite: 0.84, alpha: 1)
1103
+        if let toolTip {
1104
+            button.toolTip = toolTip
1105
+        }
1106
+        let symbolConfig = NSImage.SymbolConfiguration(pointSize: pointSize, weight: .medium)
1107
+        if let base = NSImage(systemSymbolName: symbol, accessibilityDescription: symbol),
1108
+           let image = base.withSymbolConfiguration(symbolConfig) {
1109
+            image.isTemplate = true
1110
+            button.image = image
1111
+        }
1091
         button.imageScaling = .scaleProportionallyUpOrDown
1112
         button.imageScaling = .scaleProportionallyUpOrDown
1113
+        button.imagePosition = .imageOnly
1092
         button.translatesAutoresizingMaskIntoConstraints = false
1114
         button.translatesAutoresizingMaskIntoConstraints = false
1093
-        button.widthAnchor.constraint(equalToConstant: 26).isActive = true
1094
-        button.heightAnchor.constraint(equalToConstant: 26).isActive = true
1115
+        button.widthAnchor.constraint(equalToConstant: dimension).isActive = true
1116
+        button.heightAnchor.constraint(equalToConstant: dimension).isActive = true
1095
         return button
1117
         return button
1096
     }
1118
     }
1097
 
1119