← back to Ticket System
Ticket desktop bar: top-align tiles in left/right docks + resizable/expandable bar
d9487c831303c7af2e2e8a11bebe4339b226c461 · 2026-09-03 11:23:49 -0700 · Steve Abrams
- Left/Right vertical docks now top-pin the tile group (alignTop) instead of centering
it (alignCenterY stays for the Top bar) — no more dead space above the tiles.
- New 'Bar Bigger (expand)' / 'Bar Smaller' dropdown controls resize the WHOLE bar:
width in the vertical docks (ticketBarVWidth, 180–700) and height in the Top bar
(ticketBarHeight, 28–300); persisted per mode. Added a 'Change Dock' menu item too.
- 'Wider/Narrower' relabeled 'Tile Wider/Narrower' to distinguish tile vs bar sizing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XNcHvXXepEQar7Qsb7GGy
Files touched
M desktop-bar/TicketBar.swift
Diff
commit d9487c831303c7af2e2e8a11bebe4339b226c461
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 3 11:23:49 2026 -0700
Ticket desktop bar: top-align tiles in left/right docks + resizable/expandable bar
- Left/Right vertical docks now top-pin the tile group (alignTop) instead of centering
it (alignCenterY stays for the Top bar) — no more dead space above the tiles.
- New 'Bar Bigger (expand)' / 'Bar Smaller' dropdown controls resize the WHOLE bar:
width in the vertical docks (ticketBarVWidth, 180–700) and height in the Top bar
(ticketBarHeight, 28–300); persisted per mode. Added a 'Change Dock' menu item too.
- 'Wider/Narrower' relabeled 'Tile Wider/Narrower' to distinguish tile vs bar sizing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XNcHvXXepEQar7Qsb7GGy
---
desktop-bar/TicketBar.swift | 43 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 36 insertions(+), 7 deletions(-)
diff --git a/desktop-bar/TicketBar.swift b/desktop-bar/TicketBar.swift
index f523b331..553e7d39 100644
--- a/desktop-bar/TicketBar.swift
+++ b/desktop-bar/TicketBar.swift
@@ -85,6 +85,8 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
private let vbarWidth: CGFloat = 300
private var contentContainer: NSView!
private var stackConstraints: [NSLayoutConstraint] = []
+ private var alignCenterY: NSLayoutConstraint! // vertical centering (Top mode)
+ private var alignTop: NSLayoutConstraint! // top-pinned (Left/Right docks)
private var statusDetails: [String: [String]] = [:]
private var workingDetails: [String] = []
private var latestDetail = "No activity yet"
@@ -176,13 +178,14 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
stack.translatesAutoresizingMaskIntoConstraints = false
container.clipsToBounds = true
container.addSubview(stack)
+ alignCenterY = stack.centerYAnchor.constraint(equalTo: container.centerYAnchor)
+ alignTop = stack.topAnchor.constraint(equalTo: container.topAnchor, constant: 10)
stackConstraints = [
stack.centerXAnchor.constraint(equalTo: container.centerXAnchor),
- stack.centerYAnchor.constraint(equalTo: container.centerYAnchor),
stack.leadingAnchor.constraint(greaterThanOrEqualTo: container.leadingAnchor, constant: 14),
stack.trailingAnchor.constraint(lessThanOrEqualTo: container.trailingAnchor, constant: -10)
]
- NSLayoutConstraint.activate(stackConstraints)
+ NSLayoutConstraint.activate(stackConstraints + [alignCenterY])
hamburger = NSButton(title: "☰", target: self, action: #selector(openFromHamburger))
hamburger.isBordered = false
hamburger.font = .systemFont(ofSize: 18, weight: .bold)
@@ -214,6 +217,22 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
applyPosition()
}
+ // Persisted per-mode bar size: width for the vertical docks, height for the top bar.
+ private func vBarWidth() -> CGFloat { CGFloat((UserDefaults.standard.object(forKey: "ticketBarVWidth") as? Double) ?? 300) }
+ private func topBarHeight() -> CGFloat { CGFloat((UserDefaults.standard.object(forKey: "ticketBarHeight") as? Double) ?? 38) }
+ @objc private func barBigger(_ s: NSMenuItem) { adjustBarSize(by: 1) }
+ @objc private func barSmaller(_ s: NSMenuItem) { adjustBarSize(by: -1) }
+ @objc private func cyclePositionMenu(_ s: NSMenuItem) { cyclePosition() }
+ // Expand/shrink the WHOLE bar: cross-axis width (left/right) or height (top).
+ private func adjustBarSize(by dir: CGFloat) {
+ if barPosition == "left" || barPosition == "right" {
+ UserDefaults.standard.set(Double(min(700, max(180, vBarWidth() + dir * 40))), forKey: "ticketBarVWidth")
+ } else if barPosition == "top" {
+ UserDefaults.standard.set(Double(min(300, max(28, topBarHeight() + dir * 16))), forKey: "ticketBarHeight")
+ }
+ applyPosition()
+ }
+
// Dock the bar top (horizontal), left/right (vertical), or collapse to a ☰ hamburger.
private func applyPosition() {
guard let screen = panel.screen ?? NSScreen.main ?? NSScreen.screens.first else { return }
@@ -238,17 +257,21 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
let vertical = (barPosition == "left" || barPosition == "right")
stack.orientation = vertical ? .vertical : .horizontal
stack.alignment = vertical ? .leading : .centerY
+ // Top-pin the tile group in the vertical docks; center it in the Top bar.
+ alignCenterY.isActive = !vertical
+ alignTop.isActive = vertical
+ let vW = self.vBarWidth()
// Tile widths: uniform in a vertical bar; restore the horizontal widths on top.
for tile in tiles {
- tile.widthConstraint.constant = vertical ? (vbarWidth - 44) : (horizWidths[tile.key] ?? tile.widthConstraint.constant)
+ tile.widthConstraint.constant = vertical ? (vW - 44) : (horizWidths[tile.key] ?? tile.widthConstraint.constant)
}
switch barPosition {
case "left":
- panel.setFrame(NSRect(x: v.minX, y: v.minY, width: vbarWidth, height: v.height), display: true)
+ panel.setFrame(NSRect(x: v.minX, y: v.minY, width: vW, height: v.height), display: true)
case "right":
- panel.setFrame(NSRect(x: v.maxX - vbarWidth, y: v.minY, width: vbarWidth, height: v.height), display: true)
+ panel.setFrame(NSRect(x: v.maxX - vW, y: v.minY, width: vW, height: v.height), display: true)
default: // top
- let barHeight: CGFloat = 38
+ let barHeight = self.topBarHeight()
let requested = CGFloat(UserDefaults.standard.double(forKey: "ticketBarYOffset"))
let offset = min(max(0, requested), max(0, v.height - barHeight))
panel.setFrame(NSRect(x: v.minX, y: v.maxY - barHeight - offset, width: v.width, height: barHeight), display: true)
@@ -390,7 +413,13 @@ private final class BarController: NSObject, NSApplicationDelegate, NSWindowDele
menu.addItem(item)
}
menu.addItem(.separator())
- for (title, action) in [("Move Left", #selector(moveLeft(_:))), ("Move Right", #selector(moveRight(_:))), ("Move Bar Up", #selector(moveBarUp(_:))), ("Move Bar Down", #selector(moveBarDown(_:))), ("Wider", #selector(wider(_:))), ("Narrower", #selector(narrower(_:)))] {
+ for (title, action) in [
+ ("Move Left", #selector(moveLeft(_:))), ("Move Right", #selector(moveRight(_:))),
+ ("Move Bar Up", #selector(moveBarUp(_:))), ("Move Bar Down", #selector(moveBarDown(_:))),
+ ("Tile Wider", #selector(wider(_:))), ("Tile Narrower", #selector(narrower(_:))),
+ ("Bar Bigger (expand)", #selector(barBigger(_:))), ("Bar Smaller", #selector(barSmaller(_:))),
+ ("Change Dock ▸ top/left/right/off", #selector(cyclePositionMenu(_:)))
+ ] {
let item = NSMenuItem(title: title, action: action, keyEquivalent: "")
item.target = self
item.representedObject = key
← 452464b2 record TK-10928 durable monitoring evidence
·
back to Ticket System
·
record TK-11188 bounded monitoring proof 737fe045 →