|
|
@@ -312,14 +312,14 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
312
|
312
|
|
|
313
|
313
|
private func configureFeatureShortcutCards() {
|
|
314
|
314
|
featureCardsRow.orientation = .horizontal
|
|
315
|
|
- featureCardsRow.spacing = 12
|
|
|
315
|
+ featureCardsRow.spacing = 16
|
|
316
|
316
|
featureCardsRow.distribution = .fillEqually
|
|
317
|
317
|
featureCardsRow.alignment = .top
|
|
318
|
318
|
featureCardsRow.translatesAutoresizingMaskIntoConstraints = false
|
|
319
|
319
|
|
|
320
|
320
|
let specs: [(symbol: String, title: String, subtitle: String, action: Selector)] = [
|
|
321
|
|
- ("briefcase.fill", "Role", "Explore similar or better job roles", #selector(didTapFeatureRole)),
|
|
322
|
|
- ("building.2.fill", "Company", "Find opportunities at other companies", #selector(didTapFeatureCompany)),
|
|
|
321
|
+ ("briefcase", "Role", "Explore similar or better job roles", #selector(didTapFeatureRole)),
|
|
|
322
|
+ ("building.2", "Company", "Find opportunities at other companies", #selector(didTapFeatureCompany)),
|
|
323
|
323
|
("chevron.left.forwardslash.chevron.right", "Skill", "Match jobs that fit your skills", #selector(didTapFeatureSkill))
|
|
324
|
324
|
]
|
|
325
|
325
|
for spec in specs {
|
|
|
@@ -2540,8 +2540,9 @@ private struct OpenAIAPIErrorResponse: Codable {
|
|
2540
|
2540
|
}
|
|
2541
|
2541
|
}
|
|
2542
|
2542
|
|
|
2543
|
|
-/// Home welcome row: three tappable shortcuts that seed the main search field (matches the reference dashboard tiles).
|
|
|
2543
|
+/// Home welcome row: three tappable shortcuts that seed the main search field (reference: white cards, pastel icon well, arrow at bottom trailing).
|
|
2544
|
2544
|
private final class FeatureShortcutCardView: NSView {
|
|
|
2545
|
+ private static let cardCornerRadius: CGFloat = 14
|
|
2545
|
2546
|
private weak var actionTarget: AnyObject?
|
|
2546
|
2547
|
private var actionSelector: Selector
|
|
2547
|
2548
|
|
|
|
@@ -2551,37 +2552,44 @@ private final class FeatureShortcutCardView: NSView {
|
|
2551
|
2552
|
super.init(frame: .zero)
|
|
2552
|
2553
|
translatesAutoresizingMaskIntoConstraints = false
|
|
2553
|
2554
|
wantsLayer = true
|
|
2554
|
|
- layer?.cornerRadius = 14
|
|
|
2555
|
+ layer?.cornerRadius = Self.cardCornerRadius
|
|
2555
|
2556
|
if #available(macOS 11.0, *) {
|
|
2556
|
2557
|
layer?.cornerCurve = .continuous
|
|
2557
|
2558
|
}
|
|
2558
|
2559
|
layer?.backgroundColor = NSColor.white.cgColor
|
|
2559
|
2560
|
layer?.masksToBounds = false
|
|
2560
|
|
- layer?.shadowColor = NSColor.black.withAlphaComponent(0.12).cgColor
|
|
|
2561
|
+ layer?.borderWidth = 1
|
|
|
2562
|
+ // `#EDF2F7` — light card stroke.
|
|
|
2563
|
+ layer?.borderColor = NSColor(srgbRed: 237 / 255, green: 242 / 255, blue: 247 / 255, alpha: 1).cgColor
|
|
|
2564
|
+ layer?.shadowColor = NSColor.black.withAlphaComponent(0.06).cgColor
|
|
2561
|
2565
|
layer?.shadowOffset = CGSize(width: 0, height: 2)
|
|
2562
|
|
- layer?.shadowRadius = 10
|
|
|
2566
|
+ layer?.shadowRadius = 12
|
|
2563
|
2567
|
layer?.shadowOpacity = 1
|
|
2564
|
2568
|
|
|
2565
|
|
- let brandBlue = NSColor(srgbRed: 37 / 255, green: 87 / 255, blue: 167 / 255, alpha: 1)
|
|
2566
|
|
- let iconWellColor = NSColor(srgbRed: 220 / 255, green: 235 / 255, blue: 252 / 255, alpha: 1)
|
|
2567
|
|
- let secondary = NSColor(srgbRed: 118 / 255, green: 118 / 255, blue: 118 / 255, alpha: 1)
|
|
|
2569
|
+ // `#0047AB` — primary title / icons / arrow.
|
|
|
2570
|
+ let primaryBlue = NSColor(srgbRed: 0 / 255, green: 71 / 255, blue: 171 / 255, alpha: 1)
|
|
|
2571
|
+ // `#EBF2FF` — circular icon well.
|
|
|
2572
|
+ let iconWellColor = NSColor(srgbRed: 235 / 255, green: 242 / 255, blue: 255 / 255, alpha: 1)
|
|
|
2573
|
+ // `#5D6D7E` — muted description.
|
|
|
2574
|
+ let secondary = NSColor(srgbRed: 93 / 255, green: 109 / 255, blue: 126 / 255, alpha: 1)
|
|
2568
|
2575
|
|
|
|
2576
|
+ let iconSize: CGFloat = 48
|
|
2569
|
2577
|
let iconHost = NSView()
|
|
2570
|
2578
|
iconHost.translatesAutoresizingMaskIntoConstraints = false
|
|
2571
|
2579
|
iconHost.wantsLayer = true
|
|
2572
|
2580
|
iconHost.layer?.backgroundColor = iconWellColor.cgColor
|
|
2573
|
|
- iconHost.layer?.cornerRadius = 22
|
|
|
2581
|
+ iconHost.layer?.cornerRadius = iconSize / 2
|
|
2574
|
2582
|
|
|
2575
|
2583
|
let icon = NSImageView()
|
|
2576
|
2584
|
icon.translatesAutoresizingMaskIntoConstraints = false
|
|
2577
|
|
- icon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 16, weight: .semibold)
|
|
|
2585
|
+ icon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 18, weight: .regular)
|
|
2578
|
2586
|
icon.image = NSImage(systemSymbolName: symbolName, accessibilityDescription: nil)
|
|
2579
|
|
- icon.contentTintColor = brandBlue
|
|
|
2587
|
+ icon.contentTintColor = primaryBlue
|
|
2580
|
2588
|
iconHost.addSubview(icon)
|
|
2581
|
2589
|
|
|
2582
|
2590
|
let titleField = NSTextField(wrappingLabelWithString: title)
|
|
2583
|
2591
|
titleField.font = .systemFont(ofSize: 15, weight: .bold)
|
|
2584
|
|
- titleField.textColor = brandBlue
|
|
|
2592
|
+ titleField.textColor = primaryBlue
|
|
2585
|
2593
|
titleField.maximumNumberOfLines = 1
|
|
2586
|
2594
|
titleField.isEditable = false
|
|
2587
|
2595
|
titleField.isBordered = false
|
|
|
@@ -2589,50 +2597,60 @@ private final class FeatureShortcutCardView: NSView {
|
|
2589
|
2597
|
titleField.alignment = .left
|
|
2590
|
2598
|
|
|
2591
|
2599
|
let subtitleField = NSTextField(wrappingLabelWithString: subtitle)
|
|
2592
|
|
- subtitleField.font = .systemFont(ofSize: 11, weight: .regular)
|
|
|
2600
|
+ subtitleField.font = .systemFont(ofSize: 12, weight: .regular)
|
|
2593
|
2601
|
subtitleField.textColor = secondary
|
|
2594
|
2602
|
subtitleField.maximumNumberOfLines = 2
|
|
2595
|
2603
|
subtitleField.isEditable = false
|
|
2596
|
2604
|
subtitleField.isBordered = false
|
|
2597
|
2605
|
subtitleField.drawsBackground = false
|
|
2598
|
2606
|
subtitleField.alignment = .left
|
|
2599
|
|
- subtitleField.preferredMaxLayoutWidth = 160
|
|
2600
|
|
-
|
|
2601
|
|
- let textColumn = NSStackView(views: [titleField, subtitleField])
|
|
2602
|
|
- textColumn.orientation = .vertical
|
|
2603
|
|
- textColumn.spacing = 4
|
|
2604
|
|
- textColumn.alignment = .leading
|
|
2605
|
|
- textColumn.translatesAutoresizingMaskIntoConstraints = false
|
|
2606
|
|
- textColumn.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
2607
|
|
- textColumn.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
2607
|
+ subtitleField.lineBreakMode = .byWordWrapping
|
|
|
2608
|
+ subtitleField.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
|
2609
|
+ subtitleField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
2608
|
2610
|
|
|
2609
|
2611
|
let chevron = NSImageView()
|
|
2610
|
2612
|
chevron.translatesAutoresizingMaskIntoConstraints = false
|
|
2611
|
|
- chevron.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 13, weight: .semibold)
|
|
|
2613
|
+ chevron.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
|
|
2612
|
2614
|
chevron.image = NSImage(systemSymbolName: "arrow.right", accessibilityDescription: nil)
|
|
2613
|
|
- chevron.contentTintColor = brandBlue
|
|
|
2615
|
+ chevron.contentTintColor = primaryBlue
|
|
2614
|
2616
|
chevron.setContentHuggingPriority(.required, for: .horizontal)
|
|
2615
|
2617
|
chevron.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
2616
|
2618
|
|
|
|
2619
|
+ let subtitleRow = NSStackView(views: [subtitleField, chevron])
|
|
|
2620
|
+ subtitleRow.orientation = .horizontal
|
|
|
2621
|
+ subtitleRow.spacing = 10
|
|
|
2622
|
+ subtitleRow.alignment = .bottom
|
|
|
2623
|
+ subtitleRow.distribution = .fill
|
|
|
2624
|
+ subtitleRow.translatesAutoresizingMaskIntoConstraints = false
|
|
|
2625
|
+
|
|
|
2626
|
+ let textColumn = NSStackView(views: [titleField, subtitleRow])
|
|
|
2627
|
+ textColumn.orientation = .vertical
|
|
|
2628
|
+ textColumn.spacing = 6
|
|
|
2629
|
+ textColumn.alignment = .leading
|
|
|
2630
|
+ textColumn.translatesAutoresizingMaskIntoConstraints = false
|
|
|
2631
|
+ textColumn.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
|
|
2632
|
+ textColumn.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
|
|
2633
|
+
|
|
2617
|
2634
|
iconHost.setContentHuggingPriority(.required, for: .horizontal)
|
|
2618
|
2635
|
iconHost.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
2619
|
2636
|
|
|
2620
|
|
- let row = NSStackView(views: [iconHost, textColumn, chevron])
|
|
|
2637
|
+ let row = NSStackView(views: [iconHost, textColumn])
|
|
2621
|
2638
|
row.orientation = .horizontal
|
|
2622
|
|
- row.spacing = 12
|
|
|
2639
|
+ row.spacing = 16
|
|
2623
|
2640
|
row.alignment = .centerY
|
|
2624
|
2641
|
row.distribution = .fill
|
|
2625
|
2642
|
row.translatesAutoresizingMaskIntoConstraints = false
|
|
2626
|
2643
|
addSubview(row)
|
|
2627
|
2644
|
|
|
|
2645
|
+ let inset: CGFloat = 22
|
|
2628
|
2646
|
NSLayoutConstraint.activate([
|
|
2629
|
|
- row.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 14),
|
|
2630
|
|
- row.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -14),
|
|
2631
|
|
- row.topAnchor.constraint(equalTo: topAnchor, constant: 16),
|
|
2632
|
|
- row.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),
|
|
|
2647
|
+ row.leadingAnchor.constraint(equalTo: leadingAnchor, constant: inset),
|
|
|
2648
|
+ row.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -inset),
|
|
|
2649
|
+ row.topAnchor.constraint(equalTo: topAnchor, constant: inset),
|
|
|
2650
|
+ row.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -inset),
|
|
2633
|
2651
|
|
|
2634
|
|
- iconHost.widthAnchor.constraint(equalToConstant: 44),
|
|
2635
|
|
- iconHost.heightAnchor.constraint(equalToConstant: 44),
|
|
|
2652
|
+ iconHost.widthAnchor.constraint(equalToConstant: iconSize),
|
|
|
2653
|
+ iconHost.heightAnchor.constraint(equalToConstant: iconSize),
|
|
2636
|
2654
|
icon.centerXAnchor.constraint(equalTo: iconHost.centerXAnchor),
|
|
2637
|
2655
|
icon.centerYAnchor.constraint(equalTo: iconHost.centerYAnchor)
|
|
2638
|
2656
|
])
|
|
|
@@ -2651,7 +2669,8 @@ private final class FeatureShortcutCardView: NSView {
|
|
2651
|
2669
|
super.layout()
|
|
2652
|
2670
|
guard let layer = layer, bounds.width > 0, bounds.height > 0 else { return }
|
|
2653
|
2671
|
let r = bounds
|
|
2654
|
|
- layer.shadowPath = CGPath(roundedRect: r, cornerWidth: 14, cornerHeight: 14, transform: nil)
|
|
|
2672
|
+ let cr = Self.cardCornerRadius
|
|
|
2673
|
+ layer.shadowPath = CGPath(roundedRect: r, cornerWidth: cr, cornerHeight: cr, transform: nil)
|
|
2655
|
2674
|
}
|
|
2656
|
2675
|
|
|
2657
|
2676
|
override func mouseDown(with event: NSEvent) {
|