|
|
@@ -31,7 +31,7 @@ final class ProfilesListPageView: NSView {
|
|
31
|
31
|
private let documentView = ProfilesListDocumentView()
|
|
32
|
32
|
private let contentStack = NSStackView()
|
|
33
|
33
|
private let emptyStateLabel = NSTextField(wrappingLabelWithString: "")
|
|
34
|
|
- private let addButton = ProfilesPrimaryButton(title: "Add new profile →", target: nil, action: nil)
|
|
|
34
|
+ private let addButton = ProfilesPrimaryButton(title: "Add new profile", showsTrailingArrow: true, target: nil, action: nil)
|
|
35
|
35
|
|
|
36
|
36
|
override var userInterfaceLayoutDirection: NSUserInterfaceLayoutDirection {
|
|
37
|
37
|
get { .leftToRight }
|
|
|
@@ -89,6 +89,9 @@ final class ProfilesListPageView: NSView {
|
|
89
|
89
|
addButton.target = self
|
|
90
|
90
|
addButton.action = #selector(didTapAdd)
|
|
91
|
91
|
addButton.translatesAutoresizingMaskIntoConstraints = false
|
|
|
92
|
+ // Keep the pill at intrinsic width so title + arrow stay grouped and centered; otherwise a wide stack pins text and icon to opposite edges.
|
|
|
93
|
+ addButton.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
94
|
+ addButton.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
92
|
95
|
|
|
93
|
96
|
let titleSubtitleStack = NSStackView(views: [title, subtitle])
|
|
94
|
97
|
titleSubtitleStack.orientation = .vertical
|
|
|
@@ -253,6 +256,9 @@ private final class ProfileListRowView: NSView {
|
|
253
|
256
|
// MARK: - Primary CTA (matches profile page button)
|
|
254
|
257
|
|
|
255
|
258
|
private final class ProfilesPrimaryButton: NSButton {
|
|
|
259
|
+ /// Horizontal padding around title + icon. Extra trailing inset keeps the SF arrow off the capsule curve (`masksToBounds` can clip at the ends).
|
|
|
260
|
+ private static let intrinsicPadding = NSEdgeInsets(top: 12, left: 28, bottom: 12, right: 44)
|
|
|
261
|
+
|
|
256
|
262
|
private var trackingArea: NSTrackingArea?
|
|
257
|
263
|
private var didPushCursor = false
|
|
258
|
264
|
|
|
|
@@ -266,26 +272,50 @@ private final class ProfilesPrimaryButton: NSButton {
|
|
266
|
272
|
commonInit()
|
|
267
|
273
|
}
|
|
268
|
274
|
|
|
269
|
|
- convenience init(title: String, target: AnyObject?, action: Selector?) {
|
|
|
275
|
+ convenience init(title: String, showsTrailingArrow: Bool = false, target: AnyObject?, action: Selector?) {
|
|
270
|
276
|
self.init(frame: .zero)
|
|
271
|
277
|
self.title = title
|
|
272
|
278
|
self.target = target
|
|
273
|
279
|
self.action = action
|
|
|
280
|
+ if showsTrailingArrow {
|
|
|
281
|
+ imagePosition = .imageTrailing
|
|
|
282
|
+ let symbolConfig = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
|
|
|
283
|
+ image = NSImage(systemSymbolName: "arrow.right", accessibilityDescription: nil)?
|
|
|
284
|
+ .withSymbolConfiguration(symbolConfig)
|
|
|
285
|
+ }
|
|
274
|
286
|
}
|
|
275
|
287
|
|
|
276
|
288
|
private func commonInit() {
|
|
277
|
289
|
bezelStyle = .rounded
|
|
278
|
290
|
isBordered = false
|
|
279
|
|
- font = .systemFont(ofSize: 16, weight: .semibold)
|
|
|
291
|
+ font = .systemFont(ofSize: 15, weight: .semibold)
|
|
280
|
292
|
contentTintColor = .white
|
|
281
|
293
|
wantsLayer = true
|
|
282
|
|
- layer?.cornerRadius = 14
|
|
|
294
|
+ layer?.masksToBounds = true
|
|
283
|
295
|
if #available(macOS 11.0, *) {
|
|
284
|
296
|
layer?.cornerCurve = .continuous
|
|
285
|
297
|
}
|
|
286
|
298
|
layer?.backgroundColor = ProfilesListPalette.brandBlue.cgColor
|
|
287
|
299
|
}
|
|
288
|
300
|
|
|
|
301
|
+ override var intrinsicContentSize: NSSize {
|
|
|
302
|
+ let base = super.intrinsicContentSize
|
|
|
303
|
+ let p = Self.intrinsicPadding
|
|
|
304
|
+ // `NSButton` intrinsic width can sit a few points tight vs. the symbol’s painted bounds; add slack so the arrow never kisses the pill edge.
|
|
|
305
|
+ let trailingSlack: CGFloat = image != nil ? 10 : 0
|
|
|
306
|
+ return NSSize(
|
|
|
307
|
+ width: base.width + p.left + p.right + trailingSlack,
|
|
|
308
|
+ height: base.height + p.top + p.bottom
|
|
|
309
|
+ )
|
|
|
310
|
+ }
|
|
|
311
|
+
|
|
|
312
|
+ override func layout() {
|
|
|
313
|
+ super.layout()
|
|
|
314
|
+ let h = bounds.height
|
|
|
315
|
+ guard h > 1 else { return }
|
|
|
316
|
+ layer?.cornerRadius = h / 2
|
|
|
317
|
+ }
|
|
|
318
|
+
|
|
289
|
319
|
override func updateTrackingAreas() {
|
|
290
|
320
|
super.updateTrackingAreas()
|
|
291
|
321
|
if let trackingArea { removeTrackingArea(trackingArea) }
|