feat: pin a specific meeting from the sketchybar popup
Clicking a meeting in the right-click popup pins it to the bar
display. Clicking it again unpins. The pin auto-clears when the
event ends.
Assisted-by: Claude Opus 4.6 via Claude Code
diff --git a/.config/sketchybar/meetingbar.swift b/.config/sketchybar/meetingbar.swift
index c0194365..2ed2d2b7 100755
--- a/.config/sketchybar/meetingbar.swift
+++ b/.config/sketchybar/meetingbar.swift
@@ -7,8 +7,8 @@ Output format:
{
"primary": { "display": "Standup ends in 5 minutes", "url": "https://..." },
"events": [
- { "time": "9:00 - 9:30 AM", "title": "Standup", "url": "https://..." },
- { "time": "10:00 - 11:00 AM", "title": "Design Review", "url": null }
+ { "time": "9:00 - 9:30 AM", "title": "Standup", "display": "Standup ends in 5 minutes", "url": "https://...", "current": true, "id": "ABC123" },
+ { "time": "10:00 - 11:00 AM", "title": "Design Review", "display": "Design Review in 35 minutes", "url": null, "current": false, "id": "DEF456" }
]
}
@@ -231,9 +231,22 @@ let calendarTitle = CommandLine.arguments[1]
do {
let manager = try MeetingBar(calendarTitle: calendarTitle)
let events = try manager.remainingEventsToday()
- let primary = manager.primaryEvent(from: events)
+ var primary = manager.primaryEvent(from: events)
let currentDate = Date()
+ // Check for pinned event override.
+ let tmpDir = ProcessInfo.processInfo.environment["TMPDIR"] ?? NSTemporaryDirectory()
+ let pinPath = tmpDir + "meetingbar_pin"
+
+ if let pinnedID = try? String(contentsOfFile: pinPath, encoding: .utf8).trimmingCharacters(in: .whitespacesAndNewlines),
+ !pinnedID.isEmpty {
+ if let pinnedEvent = events.first(where: { $0.eventIdentifier == pinnedID }) {
+ primary = pinnedEvent
+ } else {
+ try? FileManager.default.removeItem(atPath: pinPath)
+ }
+ }
+
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "h:mm a"
@@ -264,7 +277,13 @@ do {
let title = event.title ?? "Untitled Event"
let url = extractMeetingURL(from: event)
let isCurrent = currentDate >= event.startDate && currentDate <= event.endDate
- eventJSONs.append("{ \"time\": \(jsonString(time)), \"title\": \(jsonString(title)), \"url\": \(jsonStringOrNull(url)), \"current\": \(isCurrent) }")
+ let display: String
+ if isCurrent {
+ display = "\(title) ends \(formatTimeUntil(event.endDate, from: currentDate))"
+ } else {
+ display = "\(title) \(formatTimeUntil(event.startDate, from: currentDate))"
+ }
+ eventJSONs.append("{ \"time\": \(jsonString(time)), \"title\": \(jsonString(title)), \"display\": \(jsonString(display)), \"url\": \(jsonStringOrNull(url)), \"current\": \(isCurrent), \"id\": \(jsonString(event.eventIdentifier)) }")
}
let eventsJSON = "[\(eventJSONs.joined(separator: ", "))]"
diff --git a/.config/sketchybar/plugins/meetingbar_click.sh b/.config/sketchybar/plugins/meetingbar_click.sh
index 64768010..52ff76f2 100755
--- a/.config/sketchybar/plugins/meetingbar_click.sh
+++ b/.config/sketchybar/plugins/meetingbar_click.sh
@@ -1,6 +1,7 @@
#!/bin/sh
CALENDAR=alpha.chen@gusto.com
+PIN_FILE="${TMPDIR}meetingbar_pin"
if [ "$BUTTON" = "right" ]; then
# Toggle popup off if already open
@@ -12,6 +13,11 @@ if [ "$BUTTON" = "right" ]; then
JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR")
+ PINNED_ID=""
+ if [ -f "$PIN_FILE" ]; then
+ PINNED_ID=$(cat "$PIN_FILE")
+ fi
+
# Remove old popup items
sketchybar --remove '/meetingbar\.popup\./' 2>/dev/null
@@ -27,32 +33,28 @@ if [ "$BUTTON" = "right" ]; then
while IFS= read -r EVENT; do
TIME=$(echo "$EVENT" | jq -r '.time')
TITLE=$(echo "$EVENT" | jq -r '.title')
- URL=$(echo "$EVENT" | jq -r '.url // empty')
+ EVENT_ID=$(echo "$EVENT" | jq -r '.id')
CURRENT=$(echo "$EVENT" | jq -r '.current')
ITEM_NAME="meetingbar.popup.$INDEX"
LABEL="$TIME $TITLE"
ICON=""
- if [ "$CURRENT" = "true" ]; then
+ if [ "$EVENT_ID" = "$PINNED_ID" ]; then
+ ICON="📌 "
+ elif [ "$CURRENT" = "true" ]; then
ICON="▶ "
fi
- if [ -n "$URL" ]; then
- sketchybar --add item "$ITEM_NAME" popup.meetingbar \
- --set "$ITEM_NAME" \
- icon="$ICON" \
- icon.padding_left=6 \
- label="$LABEL" \
- label.padding_right=6 \
- click_script="open '$URL'; sketchybar --set meetingbar popup.drawing=off"
- else
- sketchybar --add item "$ITEM_NAME" popup.meetingbar \
- --set "$ITEM_NAME" \
- icon="$ICON" \
- icon.padding_left=6 \
- label="$LABEL" \
- label.padding_right=6
- fi
+ # Toggle pin: unpin if already pinned, pin otherwise.
+ CLICK="PIN=\${TMPDIR}meetingbar_pin; if [ -f \"\$PIN\" ] && [ \"\$(cat \"\$PIN\")\" = '${EVENT_ID}' ]; then rm \"\$PIN\"; else printf '%s' '${EVENT_ID}' > \"\$PIN\"; fi; sketchybar --set meetingbar popup.drawing=off; sketchybar --update"
+
+ sketchybar --add item "$ITEM_NAME" popup.meetingbar \
+ --set "$ITEM_NAME" \
+ icon="$ICON" \
+ icon.padding_left=6 \
+ label="$LABEL" \
+ label.padding_right=6 \
+ click_script="$CLICK"
INDEX=$((INDEX + 1))
done <<< "$(echo "$JSON" | jq -c '.events[]')"
@@ -60,7 +62,7 @@ if [ "$BUTTON" = "right" ]; then
sketchybar --set meetingbar popup.drawing=on
else
- # Left click: open the primary event's meeting URL
+ # Left click: open the displayed event's meeting URL.
JSON=$("$CONFIG_DIR/meetingbar.swift" "$CALENDAR")
URL=$(echo "$JSON" | jq -r '.primary.url // empty')