|
|
@@ -26,8 +26,6 @@ class ViewController: NSViewController {
|
|
26
|
26
|
private let chromeUnifiedBackground = NSColor(calibratedRed: 22 / 255, green: 23 / 255, blue: 26 / 255, alpha: 1)
|
|
27
|
27
|
private let searchPillBackground = NSColor.white.withAlphaComponent(0.06)
|
|
28
|
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
|
29
|
private let appShellCornerRadius: CGFloat = 20
|
|
32
|
30
|
private let homeChromeHeaderHeight: CGFloat = 56
|
|
33
|
31
|
private let nativeTrafficLightsLeading: CGFloat = 14
|
|
|
@@ -747,22 +745,35 @@ class ViewController: NSViewController {
|
|
747
|
745
|
searchPill.layer?.cornerRadius = 10
|
|
748
|
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
|
756
|
let leftTopBarCluster = NSStackView()
|
|
751
|
757
|
leftTopBarCluster.orientation = .horizontal
|
|
752
|
|
- leftTopBarCluster.spacing = 10
|
|
|
758
|
+ leftTopBarCluster.spacing = 0
|
|
753
|
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
|
772
|
let rightTopBarCluster = NSStackView()
|
|
760
|
773
|
rightTopBarCluster.orientation = .horizontal
|
|
761
|
|
- rightTopBarCluster.spacing = 8
|
|
|
774
|
+ rightTopBarCluster.spacing = 10
|
|
762
|
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
|
778
|
let profileChip = NSButton(title: String((profile?.name ?? "H").prefix(1)).uppercased(), target: self, action: #selector(logoutTapped))
|
|
768
|
779
|
profileChip.isBordered = false
|
|
|
@@ -772,7 +783,7 @@ class ViewController: NSViewController {
|
|
772
|
783
|
profileChip.contentTintColor = primaryText
|
|
773
|
784
|
profileChip.font = .systemFont(ofSize: 14, weight: .bold)
|
|
774
|
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
|
788
|
let welcome = makeLabel("Home", size: 15, color: secondaryText, weight: .medium, centered: false)
|
|
778
|
789
|
let timeTitle = makeLabel("--:--", size: 56, color: primaryText, weight: .bold, centered: true)
|
|
|
@@ -829,14 +840,13 @@ class ViewController: NSViewController {
|
|
829
|
840
|
content.addSubview(topBarDivider)
|
|
830
|
841
|
content.addSubview(contentColumn)
|
|
831
|
842
|
|
|
832
|
|
- [brandStack, leftTopBarCluster, rightTopBarCluster, searchPill, search].forEach {
|
|
|
843
|
+ [brandStack, searchRow, backForwardCluster, leftTopBarCluster, rightTopBarCluster, searchPill, search].forEach {
|
|
833
|
844
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
834
|
845
|
}
|
|
835
|
846
|
[brandStack].forEach {
|
|
836
|
847
|
shell.addSubview($0)
|
|
837
|
848
|
}
|
|
838
|
|
- [leftTopBarCluster, rightTopBarCluster, searchPill, search].forEach {
|
|
839
|
|
- $0.translatesAutoresizingMaskIntoConstraints = false
|
|
|
849
|
+ [searchRow, rightTopBarCluster, search].forEach {
|
|
840
|
850
|
topBar.addSubview($0)
|
|
841
|
851
|
}
|
|
842
|
852
|
[welcome, timeTitle, dateTitle, actions, panel, panelHeader, meetingsStatus, noMeeting, meetingsScrollView, openRecordings].forEach {
|
|
|
@@ -850,9 +860,12 @@ class ViewController: NSViewController {
|
|
850
|
860
|
meetingsScrollView.documentView = meetingsDocument
|
|
851
|
861
|
meetingsDocument.addSubview(meetingsStack)
|
|
852
|
862
|
|
|
|
863
|
+ let searchRowCenterX = searchRow.centerXAnchor.constraint(equalTo: topBar.centerXAnchor)
|
|
|
864
|
+ searchRowCenterX.priority = .defaultHigh
|
|
|
865
|
+
|
|
853
|
866
|
NSLayoutConstraint.activate([
|
|
854
|
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
|
869
|
brandStack.centerYAnchor.constraint(equalTo: chromeHeader.centerYAnchor, constant: -1),
|
|
857
|
870
|
|
|
858
|
871
|
topBar.topAnchor.constraint(equalTo: content.topAnchor),
|
|
|
@@ -869,18 +882,17 @@ class ViewController: NSViewController {
|
|
869
|
882
|
contentColumn.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 8),
|
|
870
|
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
|
891
|
rightTopBarCluster.trailingAnchor.constraint(equalTo: topBar.trailingAnchor, constant: -12),
|
|
876
|
892
|
rightTopBarCluster.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
|
|
877
|
893
|
|
|
878
|
|
- searchPill.centerXAnchor.constraint(equalTo: topBar.centerXAnchor),
|
|
879
|
|
- searchPill.centerYAnchor.constraint(equalTo: topBar.centerYAnchor),
|
|
880
|
894
|
searchPill.heightAnchor.constraint(equalToConstant: 32),
|
|
881
|
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
|
896
|
search.leadingAnchor.constraint(equalTo: searchPill.leadingAnchor, constant: 12),
|
|
885
|
897
|
search.trailingAnchor.constraint(equalTo: searchPill.trailingAnchor, constant: -12),
|
|
886
|
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
|
1079
|
button.isBordered = false
|
|
|
1080
|
+ button.focusRingType = .none
|
|
1067
|
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
|
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
|
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
|
1098
|
let button = NSButton(title: "", target: action == nil ? nil : self, action: action)
|
|
1083
|
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
|
1112
|
button.imageScaling = .scaleProportionallyUpOrDown
|
|
|
1113
|
+ button.imagePosition = .imageOnly
|
|
1092
|
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
|
1117
|
return button
|
|
1096
|
1118
|
}
|
|
1097
|
1119
|
|