|
@@ -8,6 +8,7 @@ import Cocoa
|
|
|
final class DashboardView: NSView {
|
|
final class DashboardView: NSView {
|
|
|
private let contentStack = NSStackView()
|
|
private let contentStack = NSStackView()
|
|
|
private let documentContainer = NSView()
|
|
private let documentContainer = NSView()
|
|
|
|
|
+ private let chromeContainer = NSView()
|
|
|
private let sidebar = NSStackView()
|
|
private let sidebar = NSStackView()
|
|
|
private let mainColumn = NSStackView()
|
|
private let mainColumn = NSStackView()
|
|
|
private let greetingLabel = NSTextField(labelWithString: "")
|
|
private let greetingLabel = NSTextField(labelWithString: "")
|
|
@@ -17,6 +18,8 @@ final class DashboardView: NSView {
|
|
|
private let recommendationsStack = NSStackView()
|
|
private let recommendationsStack = NSStackView()
|
|
|
private let insightsStack = NSStackView()
|
|
private let insightsStack = NSStackView()
|
|
|
private let scrollView = NSScrollView()
|
|
private let scrollView = NSScrollView()
|
|
|
|
|
+ private var recommendationsWidthConstraint: NSLayoutConstraint?
|
|
|
|
|
+ private var insightsWidthConstraint: NSLayoutConstraint?
|
|
|
|
|
|
|
|
override init(frame frameRect: NSRect) {
|
|
override init(frame frameRect: NSRect) {
|
|
|
super.init(frame: frameRect)
|
|
super.init(frame: frameRect)
|
|
@@ -54,12 +57,18 @@ final class DashboardView: NSView {
|
|
|
contentStack.orientation = .horizontal
|
|
contentStack.orientation = .horizontal
|
|
|
contentStack.spacing = 20
|
|
contentStack.spacing = 20
|
|
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
|
contentStack.translatesAutoresizingMaskIntoConstraints = false
|
|
|
- contentStack.edgeInsets = NSEdgeInsets(top: 20, left: 20, bottom: 24, right: 20)
|
|
|
|
|
|
|
+ contentStack.alignment = .top
|
|
|
|
|
+ contentStack.edgeInsets = NSEdgeInsets(top: 24, left: 24, bottom: 24, right: 24)
|
|
|
|
|
|
|
|
documentContainer.translatesAutoresizingMaskIntoConstraints = true
|
|
documentContainer.translatesAutoresizingMaskIntoConstraints = true
|
|
|
documentContainer.autoresizingMask = [.width]
|
|
documentContainer.autoresizingMask = [.width]
|
|
|
documentContainer.frame = NSRect(x: 0, y: 0, width: 1040, height: 900)
|
|
documentContainer.frame = NSRect(x: 0, y: 0, width: 1040, height: 900)
|
|
|
- documentContainer.addSubview(contentStack)
|
|
|
|
|
|
|
+ chromeContainer.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
+ chromeContainer.wantsLayer = true
|
|
|
|
|
+ chromeContainer.layer?.backgroundColor = NSColor(calibratedRed: 0.03, green: 0.08, blue: 0.2, alpha: 1).cgColor
|
|
|
|
|
+ chromeContainer.layer?.cornerRadius = 18
|
|
|
|
|
+ documentContainer.addSubview(chromeContainer)
|
|
|
|
|
+ chromeContainer.addSubview(contentStack)
|
|
|
scrollView.documentView = documentContainer
|
|
scrollView.documentView = documentContainer
|
|
|
|
|
|
|
|
sidebar.orientation = .vertical
|
|
sidebar.orientation = .vertical
|
|
@@ -96,6 +105,7 @@ final class DashboardView: NSView {
|
|
|
lowerSection.orientation = .horizontal
|
|
lowerSection.orientation = .horizontal
|
|
|
lowerSection.spacing = 12
|
|
lowerSection.spacing = 12
|
|
|
lowerSection.alignment = .top
|
|
lowerSection.alignment = .top
|
|
|
|
|
+ lowerSection.distribution = .fill
|
|
|
lowerSection.translatesAutoresizingMaskIntoConstraints = false
|
|
lowerSection.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
|
|
|
|
let recommendationsBox = sectionBox(title: "Recommended for You", content: recommendationsStack)
|
|
let recommendationsBox = sectionBox(title: "Recommended for You", content: recommendationsStack)
|
|
@@ -121,14 +131,19 @@ final class DashboardView: NSView {
|
|
|
scrollView.topAnchor.constraint(equalTo: topAnchor),
|
|
scrollView.topAnchor.constraint(equalTo: topAnchor),
|
|
|
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
|
|
|
|
|
|
- contentStack.leadingAnchor.constraint(equalTo: documentContainer.leadingAnchor),
|
|
|
|
|
- contentStack.trailingAnchor.constraint(equalTo: documentContainer.trailingAnchor),
|
|
|
|
|
- contentStack.topAnchor.constraint(equalTo: documentContainer.topAnchor),
|
|
|
|
|
- contentStack.bottomAnchor.constraint(equalTo: documentContainer.bottomAnchor),
|
|
|
|
|
- contentStack.widthAnchor.constraint(equalTo: documentContainer.widthAnchor),
|
|
|
|
|
|
|
+ chromeContainer.topAnchor.constraint(equalTo: documentContainer.topAnchor, constant: 18),
|
|
|
|
|
+ chromeContainer.bottomAnchor.constraint(equalTo: documentContainer.bottomAnchor, constant: -18),
|
|
|
|
|
+ chromeContainer.centerXAnchor.constraint(equalTo: documentContainer.centerXAnchor),
|
|
|
|
|
+ chromeContainer.widthAnchor.constraint(lessThanOrEqualToConstant: 1240),
|
|
|
|
|
+ chromeContainer.widthAnchor.constraint(equalTo: documentContainer.widthAnchor, constant: -36),
|
|
|
|
|
+
|
|
|
|
|
+ contentStack.leadingAnchor.constraint(equalTo: chromeContainer.leadingAnchor),
|
|
|
|
|
+ contentStack.trailingAnchor.constraint(equalTo: chromeContainer.trailingAnchor),
|
|
|
|
|
+ contentStack.topAnchor.constraint(equalTo: chromeContainer.topAnchor),
|
|
|
|
|
+ contentStack.bottomAnchor.constraint(equalTo: chromeContainer.bottomAnchor),
|
|
|
|
|
|
|
|
sidebar.widthAnchor.constraint(equalToConstant: 225),
|
|
sidebar.widthAnchor.constraint(equalToConstant: 225),
|
|
|
- mainColumn.widthAnchor.constraint(greaterThanOrEqualToConstant: 760),
|
|
|
|
|
|
|
+ mainColumn.widthAnchor.constraint(greaterThanOrEqualToConstant: 720),
|
|
|
heroCard.widthAnchor.constraint(equalTo: mainColumn.widthAnchor),
|
|
heroCard.widthAnchor.constraint(equalTo: mainColumn.widthAnchor),
|
|
|
heroCard.heightAnchor.constraint(equalToConstant: 140),
|
|
heroCard.heightAnchor.constraint(equalToConstant: 140),
|
|
|
|
|
|
|
@@ -137,9 +152,13 @@ final class DashboardView: NSView {
|
|
|
hero.topAnchor.constraint(equalTo: heroCard.topAnchor, constant: 18),
|
|
hero.topAnchor.constraint(equalTo: heroCard.topAnchor, constant: 18),
|
|
|
hero.bottomAnchor.constraint(equalTo: heroCard.bottomAnchor, constant: -18),
|
|
hero.bottomAnchor.constraint(equalTo: heroCard.bottomAnchor, constant: -18),
|
|
|
|
|
|
|
|
- recommendationsBox.widthAnchor.constraint(equalToConstant: 510),
|
|
|
|
|
- insightsBox.widthAnchor.constraint(equalToConstant: 238)
|
|
|
|
|
|
|
+ lowerSection.widthAnchor.constraint(equalTo: mainColumn.widthAnchor)
|
|
|
])
|
|
])
|
|
|
|
|
+
|
|
|
|
|
+ recommendationsWidthConstraint = recommendationsBox.widthAnchor.constraint(equalTo: mainColumn.widthAnchor, multiplier: 0.68)
|
|
|
|
|
+ insightsWidthConstraint = insightsBox.widthAnchor.constraint(equalTo: mainColumn.widthAnchor, multiplier: 0.32, constant: -8)
|
|
|
|
|
+ recommendationsWidthConstraint?.isActive = true
|
|
|
|
|
+ insightsWidthConstraint?.isActive = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func buildHeroContent() -> NSView {
|
|
private func buildHeroContent() -> NSView {
|
|
@@ -408,7 +427,7 @@ final class DashboardView: NSView {
|
|
|
|
|
|
|
|
private func updateDocumentLayout() {
|
|
private func updateDocumentLayout() {
|
|
|
documentContainer.layoutSubtreeIfNeeded()
|
|
documentContainer.layoutSubtreeIfNeeded()
|
|
|
- let fittingHeight = max(contentStack.fittingSize.height, bounds.height)
|
|
|
|
|
|
|
+ let fittingHeight = max(chromeContainer.fittingSize.height + 36, bounds.height)
|
|
|
documentContainer.frame = NSRect(x: 0, y: 0, width: bounds.width, height: fittingHeight)
|
|
documentContainer.frame = NSRect(x: 0, y: 0, width: bounds.width, height: fittingHeight)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|