Share your plugins #12
Replies: 110 comments 378 replies
-
Window TitleDESCRIPTION: This will display the current window's title in your bar. If the window's title is greater than 50 characters it will truncate it, if there it no title available it will fall back to the application name. This was written by @FelixKratz and Modified by me. NOTE: Assuming you are using yabai, you can quickly check window titles and app names of the current window with Updated Configuration: sketchybarrc# E V E N T S
sketchybar -m --add event window_focus \
--add event title_change
# W I N D O W T I T L E
sketchybar -m --add item title left \
--set title script="$HOME/.config/sketchybar/plugins/window_title.sh" \
--subscribe title window_focus front_app_switched space_change title_change window_title.sh#!/bin/bash
# W I N D O W T I T L E
WINDOW_TITLE=$(/opt/homebrew/bin/yabai -m query --windows --window | jq -r '.title')
if [[ $WINDOW_TITLE = "" ]]; then
WINDOW_TITLE=$(/opt/homebrew/bin/yabai -m query --windows --window | jq -r '.app')
fi
if [[ ${#WINDOW_TITLE} -gt 50 ]]; then
WINDOW_TITLE=$(echo "$WINDOW_TITLE" | cut -c 1-50)
sketchybar -m --set title label="│ $WINDOW_TITLE"…
exit 0
fi
sketchybar -m --set title label="│ $WINDOW_TITLE" yabairc # S K E T C H Y B A R E V E N T S
yabai -m signal --add event=window_focused action="sketchybar -m --trigger window_focus &> /dev/null"
yabai -m signal --add event=window_title_changed action="sketchybar -m --trigger title_change &> /dev/null" |
Beta Was this translation helpful? Give feedback.
-
24 Hour Change in Bitcoin PriceDESCRIPTION: This will display the 24hr change in price of bitcoin in your bar. sketchybarrcsketchybar -m --add item btc right \
--set btc icon= \
--set btc update_freq=20 \
--set btc script="~/.config/sketchybar/plugins/btc.sh" btc.sh#!/usr/bin/env python3
import requests
import os
response = requests.get('https://api.gemini.com/v1/pricefeed')
jsonResponse = response.json()
for i in jsonResponse:
if i["pair"] == "BTCUSD":
percentChange = str(round((float(i["percentChange24h"]) * 100), 2))
os.system('sketchybar -m --set btc label='+ percentChange + '%')
break |
Beta Was this translation helpful? Give feedback.
-
24 Hour Change in Ethereum PriceDESCRIPTION: This will display the 24hr change in price of Ethereum in your bar. sketchybarrcsketchybarrcsketchybar -m --add item eth right \
--set eth icon=ﲹ \
--set eth update_freq=20 \
--set eth script="~/.config/sketchybar/plugins/eth.sh" eth.sh#!/usr/bin/env python3
import requests
import os
response = requests.get('https://api.gemini.com/v1/pricefeed')
jsonResponse = response.json()
for i in jsonResponse:
if i["pair"] == "BTCUSD":
percentChange = str(round((float(i["percentChange24h"]) * 100), 2))
os.system('sketchybar -m --set eth label='+ percentChange + '%')
break |
Beta Was this translation helpful? Give feedback.
-
Battery StatusDESCRIPTION: This will display your current battery status. NOTE: This could probably be improved on greatly. I am not sure what an appropriate UPDATED: Updated to implement improvements made by ut0mt8 from this comment. sketchybarrcsketchybar -m --add item battery right \
--set battery update_freq=3 \
--set battery script="~/.config/sketchybar/plugins/power.sh" \
--set battery icon= power.sh#!/bin/bash
. ~/.cache/wal/colors.sh
BATT_PERCENT=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1)
CHARGING=$(pmset -g batt | grep 'AC Power')
if [[ $CHARGING != "" ]]; then
sketchybar -m --set battery \
icon.color=0xFF5DFE67 \
icon= \
label=$(printf "${BATT_PERCENT}%%")
exit 0
fi
[[ ${BATT_PERCENT} -gt 10 ]] && COLOR=0xFF${color5:1} || COLOR=0xFFFF0000
case ${BATT_PERCENT} in
100) ICON="" ;;
9[0-9]) ICON="" ;;
8[0-9]) ICON="" ;;
7[0-9]) ICON="" ;;
6[0-9]) ICON="" ;;
5[0-9]) ICON="" ;;
4[0-9]) ICON="" ;;
3[0-9]) ICON="" ;;
2[0-9]) ICON="" ;;
1[0-9]) ICON="" ;;
*) ICON=""
esac
sketchybar -m --set battery\
icon.color=$COLOR \
icon=$ICON \
label=$(printf "${BATT_PERCENT}%%") |
Beta Was this translation helpful? Give feedback.
-
Music InformationUpdate History:
DESCRIPTION: This will display information about the current track in the Music.app. It will update based on the NSDistributedNotificationCenter Events sent by the Music app. sketchybarrc# Add event
sketchybar -m --add event song_update com.apple.iTunes.playerInfo
# Add Music Item
sketchybar -m --add item music right \
--set music script="~/.config/sketchybar/scripts/music" \
click_script="~/.config/sketchybar/scripts/music_click" \
label.padding_right=10 \
drawing=off \
--subscribe music song_update music#!/usr/bin/env bash
# FIXME: Running an osascript on an application target opens that app
# This sleep is needed to try and ensure that theres enough time to
# quit the app before the next osascript command is called. I assume
# com.apple.iTunes.playerInfo fires off an event when the player quits
# so it imediately runs before the process is killed
sleep 1
APP_STATE=$(pgrep -x Music)
if [[ ! $APP_STATE ]]; then
sketchybar -m --set music drawing=off
exit 0
fi
PLAYER_STATE=$(osascript -e "tell application \"Music\" to set playerState to (get player state) as text")
if [[ $PLAYER_STATE == "stopped" ]]; then
sketchybar --set music drawing=off
exit 0
fi
title=$(osascript -e 'tell application "Music" to get name of current track')
artist=$(osascript -e 'tell application "Music" to get artist of current track')
# ALBUM=$(osascript -e 'tell application "Music" to get album of current track')
loved=$(osascript -l JavaScript -e "Application('Music').currentTrack().loved()")
if [[ $loved ]]; then
icon=""
fi
if [[ $PLAYER_STATE == "paused" ]]; then
icon=""
fi
if [[ $PLAYER_STATE == "playing" ]]; then
icon=""
fi
if [[ ${#title} -gt 25 ]]; then
TITLE=$(printf "$(echo $title | cut -c 1-25)…")
fi
if [[ ${#artist} -gt 25 ]]; then
ARTIST=$(printf "$(echo $artist | cut -c 1-25)…")
fi
# if [[ ${#ALBUM} -gt 25 ]]; then
# ALBUM=$(printf "$(echo $ALBUM | cut -c 1-12)…")
# fi
sketchybar -m --set music icon="$icon" \
--set music label="${title} x ${artist}" \
--set music drawing=on
music_click#!/usr/bin/env osascript
tell application "Music"
if loved of current track is true then
set loved of current track to false
do shell script "sketchybar -m --set music icon="
else
set loved of current track to true
do shell script "sketchybar -m --set music icon="
end if
end tell
delay 1
do shell script "sh $HOME/.config/sketchybar/scripts/music" |
Beta Was this translation helpful? Give feedback.
-
VPN StatusDESCRIPTION: Shows the vpn your currently connected to if any in your bar. sketchybarrcsketchybar -m --add item vpn right \
--set vpn icon= \
update_freq=5 \
script="~/.config/sketchybar/plugins/vpn.sh" vpn.sh#!/bin/bash
VPN=$(scutil --nc list | grep Connected | sed -E 's/.*"(.*)".*/\1/')
if [[ $VPN != "" ]]; then
sketchybar -m --set vpn icon= \
label="$VPN" \
drawing=on
else
sketchybar -m --set vpn drawing=off
fi |
Beta Was this translation helpful? Give feedback.
-
Mic StatusDESCRIPTION: Check and Mute/Unmute your mic. sketchybarrcsketchybar -m --add item mic right \
sketchybar -m --set mic update_freq=3 \
--set mic script="~/.config/sketchybar/plugins/mic.sh" \
--set mic click_script="~/.config/sketchybar/plugins/mic_click.sh" mic.sh#!/bin/bash
MIC_VOLUME=$(osascript -e 'input volume of (get volume settings)')
if [[ $MIC_VOLUME -eq 0 ]]; then
sketchybar -m --set mic icon=
elif [[ $MIC_VOLUME -gt 0 ]]; then
sketchybar -m --set mic icon=
fi
mic_click.sh#!/bin/bash
MIC_VOLUME=$(osascript -e 'input volume of (get volume settings)')
if [[ $MIC_VOLUME -eq 0 ]]; then
osascript -e 'set volume input volume 25'
sketchybar -m --set mic icon=
elif [[ $MIC_VOLUME -gt 0 ]]; then
osascript -e 'set volume input volume 0'
sketchybar -m --set mic icon=
fi |
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
RemindersDESCRIPTION: Show your reminders. NOTE: This is just a very basic script, but it could be extended to show the reminder, or use a different app like taskwarrior or taskell instead. sketchybarrcsketchybar -m --add item reminders right \
--set reminders update_freq=20 \
--set reminders script="~/.config/sketchybar/plugins/reminders.sh" \
--set reminders click_script="~/.config/sketchybar/plugins/reminders_click.sh" reminders.sh#!/bin/bash
REMINDERS_COUNT=$(osascript -l JavaScript -e "Application('Reminders').lists.byName('📥 Inbox').reminders.whose({completed: false}).name().length")
if [[ $REMINDERS_COUNT -gt 0 ]]; then
sketchybar -m --set reminders icon="" \
--set reminders label="$REMINDERS_COUNT"
else
sketchybar -m --set reminders icon="" \
--set reminders label=""
fi reminders_click.sh#!/bin/bash
open -a Reminders |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
Stack IndicatorDESCRIPTION: Show you Window's Stack Position. NOTE: Occasionally querying yabai can be delayed possibly related to this, which can lead to a number or dot being displayed late and overwriting the actual position in the indicator. sketchybarrc# S T A C K I N D I C A T O R
sketchybar -m --add item stack_sep center \
--add item stack center \
--set stack script="$HOME/.dotfiles/sketchybar/plugins/stack.sh" \
--subscribe stack window_focus front_app_switched space_change title_change \
--set stack_sep drawing=off \
--set stack drawing=off \
--set stack update_freq=0 stack.sh#!/bin/bash
# Exit if Not in Stack
CURRENT=$(yabai -m query --windows --window | jq '.["stack-index"]')
if [[ $CURRENT -eq 0 ]]; then
sketchybar -m --set stack label="" \
--set stack_sep drawing=off \
--set stack drawing=off
exit 0
fi
# Use Numbers in place of Dots if the Stack is greater than 10
# Use a larger font for the unicode dots
LAST=$(yabai -m query --windows --window stack.last | jq '.["stack-index"]')
if [[ $LAST -gt 10 ]]; then
sketchybar -m --set stack label.font="Iosevka Nerd Font:Bold:16.0" \
--set stack label=$(printf "[%s/%s]" "$CURRENT" "$LAST") \
--set stack_sep drawing=on \
--set stack drawing=on
exit 0
else
sketchybar -m --set stack label.font="Iosevka Nerd Font:Bold:22.0"
fi
# Create Stack Indicator
declare -a dots=()
for i in $(seq 0 $(expr $LAST - 1))
do
# Theme 1
# if [[ $i -lt $(expr $CURRENT - 1) ]]; then
# dots+="◖"
# elif [[ $i -gt $(expr $CURRENT - 1) ]]; then
# dots+="◗"
# elif [[ $i -eq $(expr $CURRENT - 1) ]]; then
# dots+="●"
# fi
# Theme 2
[[ $( expr $CURRENT - 1) -eq $i ]] && dots+="●" || dots+="○"
done
# Display Indicator
sketchybar -m --set stack label=$(printf "%s" ${dots[@]}) \
--set stack_sep drawing=on \
--set stack drawing=on |
Beta Was this translation helpful? Give feedback.
-
SKHD Modal IndicatorDESCRIPTION: Show the current SKHD Mode NOTES: You can hardcode the sketchybar commands into your skhdrc. I just use a seperate helper script to clean things up. sketchybarrc# M O D A L I N D I C A T O R
sketchybar -m --add item modal left
sketchybar -m --set modal icon=[N]
sketchybar -m --set modal icon_color =0xFF83A1F1 skhdrc# M O D E S
:: default : $HOME/.config/bin/helpers -n
:: window @ : $HOME/.config/bin/helpers -w
:: scripts @ : $HOME/.config/bin/helpers -s
# Mode Shortcuts
default, scripts < lcmd - escape ; window
window, scripts < escape ; default
default, window < lctrl - escape ; scripts helpersfunction normal_mode() {
echo "N O R M A L M O D E";
# C O L O R S
. $HOME/.cache/wal/colors.sh;
# Y A B A I
yabai -m config active_window_border_color 0xff${color5:1};
yabai -m config normal_window_border_color 0xff${color8:1};
yabai -m config insert_feedback_color 0xff${color5:1};
# S K E T C H Y B A R
sketchybar -m --bar color=0xF0${color0:1}
sketchybar -m --default label.color=0xFF${foreground:1}
sketchybar -m --default icon.color=0xFF${color5:1}
sketchybar -m --set modal icon.color=0xFF83A1F1
sketchybar -m --set modal icon="[N]"
}
# W I N D O W M O D E
function window_mode() {
echo "W I N D O W M O D E";
# C O L O R S
. $HOME/.cache/wal/colors.sh;
# Y A B A I
yabai -m config active_window_border_color 0xff${color3:1};
yabai -m config normal_window_border_color 0xff${color3:1};
yabai -m config insert_feedback_color 0xff${color3:1};
# S K E T C H Y B A R
sketchybar -m --bar color=0xF0${color3:1}
sketchybar -m --default label.color=0xFF${foreground:1}
sketchybar -m --default icon.color=0xFF${background:1}
sketchybar -m --set modal icon.color=0xFFA8CD76
sketchybar -m --set modal icon="[W]"
}
# S C R I P T S M O D E
function scripts_mode() {
echo "S C R I P T S M O D E";
# C O L O R S
. $HOME/.cache/wal/colors.sh;
# Y A B A I
yabai -m config active_window_border_color 0xff${color5:1};
yabai -m config normal_window_border_color 0xff${color5:1};
yabai -m config insert_feedback_color 0xff${color5:1};
# S K E T C H Y B A R
sketchybar -m --bar color=0xF0${color5:1}
sketchybar -m --default label.color=0xFF${foreground:1}
sketchybar -m --default icon.color=0xFF${color6:1}
sketchybar -m --set modal icon.color=0xFFF29B9B
sketchybar -m --set modal icon="[S]"
}
|
Beta Was this translation helpful? Give feedback.
-
yabai helperDESCRIPTION: shows the current yabai space, and the mode. Click the menu item to switch between the sketchybarrcsketchybar -m --add item yabai right
sketchybar -m --set yabai update_freq=3
sketchybar -m --set yabai script="~/.config/sketchybar/plugins/yabai.sh"
sketchybar -m --subscribe yabai space_change
sketchybar -m --set yabai click_script="~/.config/sketchybar/plugins/yabai_click.sh" yabai.sh#!/bin/bash
space_number=$(yabai -m query --spaces --display | jq 'map(select(."focused" == 1))[-1].index')
yabai_mode=$(yabai -m query --spaces --display | jq -r 'map(select(."focused" == 1))[-1].type')
sketchybar -m --set yabai label="$space_number:$yabai_mode" yabai_click.sh#!/bin/bash
space_number=$(yabai -m query --spaces --display | jq 'map(select(."focused" == 1))[-1].index')
yabai_mode=$(yabai -m query --spaces --display | jq -r 'map(select(."focused" == 1))[-1].type')
case "$yabai_mode" in
bsp)
yabai -m config layout stack
;;
stack)
yabai -m config layout float
;;
float)
yabai -m config layout bsp
;;
esac
new_yabai_mode=$(yabai -m query --spaces --display | jq -r 'map(select(."focused" == 1))[-1].type')
sketchybar -m --set yabai label="$space_number:$new_yabai_mode" |
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
Aerospace Spaces/Apps!!!IMPORTANT!!! Aerospace v0.14.2-Beta don't have some bugfixes which are already included in the current main branch of aerospace which are mandatory to let the plugin work correctly! I used the yabai implementation from Felix as a base (https://github.com/FelixKratz/dotfiles/blob/master/.config/sketchybar/items/spaces.lua) so I named my aerospace workspaces with a number prefix (1_{workspace_name} .. n-th_{workspace_name}) because aerospace workspace query outputs them by alphanumeric ordering. I then strip the prefix inside the plugin and because the async behaviour of Don't forget to add the event trigger for workspace changes inside the
spaces.lualocal colors = require("colors")
local icons = require("icons")
local settings = require("settings")
local app_icons = require("helpers.app_icons")
local item_order = ""
sbar.exec("aerospace list-workspaces --all", function(spaces)
for space_name in spaces:gmatch("[^\r\n]+") do
local space = sbar.add("item", "space." .. space_name, {
icon = {
font = { family = settings.font.numbers },
string = string.sub(space_name, 3),
padding_left = 7,
padding_right = 3,
color = colors.white,
highlight_color = colors.red,
},
label = {
padding_right = 12,
color = colors.grey,
highlight_color = colors.white,
font = "sketchybar-app-font:Regular:16.0",
y_offset = -1,
},
padding_right = 1,
padding_left = 1,
background = {
color = colors.bg1,
border_width = 1,
height = 26,
border_color = colors.black,
}
})
local space_bracket = sbar.add("bracket", { space.name }, {
background = {
color = colors.transparent,
border_color = colors.bg2,
height = 28,
border_width = 2
}
})
-- Padding space
local space_padding = sbar.add("item", "space.padding." .. space_name, {
script = "",
width = settings.group_paddings,
})
space:subscribe("aerospace_workspace_change", function(env)
local selected = env.FOCUSED_WORKSPACE == space_name
local color = selected and colors.grey or colors.bg2
space:set({
icon = { highlight = selected, },
label = { highlight = selected },
background = { border_color = selected and colors.black or colors.bg2 }
})
space_bracket:set({
background = { border_color = selected and colors.grey or colors.bg2 }
})
end)
space:subscribe("mouse.clicked", function()
sbar.exec("aerospace workspace " .. space_name)
end)
space:subscribe("space_windows_change", function()
sbar.exec("aerospace list-windows --format %{app-name} --workspace " .. space_name, function(windows)
print(windows)
local no_app = true
local icon_line = ""
for app in windows:gmatch("[^\r\n]+") do
no_app = false
local lookup = app_icons[app]
local icon = ((lookup == nil) and app_icons["default"] or lookup)
icon_line = icon_line .. " " .. icon
end
if (no_app) then
icon_line = " —"
end
sbar.animate("tanh", 10, function()
space:set({ label = icon_line })
end)
end)
end)
item_order = item_order .. " " .. space.name .. " " .. space_padding.name
end
sbar.exec("sketchybar --reorder apple " .. item_order .. " front_app")
end)
|
Beta Was this translation helpful? Give feedback.
-
1 - Hello, i search a widget in lua to show how many unread mail i have (i use mail official apps). |
Beta Was this translation helpful? Give feedback.
-
Icons based on kvndrsslr/sketchybar-app-font, but with consistent background ✨ |
Beta Was this translation helpful? Give feedback.
-
Connect/Disconnect GlobalProtectAn orange network icon that when is clicked when the GlobalProtect is switched on/off. ![]() --globalprotect.lua
local icons = require("icons")
local colors = require("colors")
local settings = require("settings")
local is_on = false
local globalprotect_icon = sbar.add("item", "widgets.globalprotect", {
position = "right",
padding_right = 0,
icon = {
string = icons.network,
width = 0,
align = "left",
color = colors.orange,
font = {
style = settings.font.style_map["Regular"],
size = 16.0
},
color = colors.orange
},
label = {
width = 30,
align = "left",
font = {
style = settings.font.style_map["Regular"],
size = 14.0
},
color = colors.orange
},
})
local globalprotect_bracket = sbar.add("bracket", "widgets.globalprotect.bracket", {
globalprotect_icon.name
}, {
background = { color = colors.bar_color,
border_color = colors.orange,
border_width = colors.border_width
},
popup = { align = "center" }
})
sbar.add("item", "widgets.globalprotect.padding", {
position = "right",
width = settings.group_paddings
})
local function runScript()
os.execute([[
osascript -e '
tell application "System Events" to tell process "GlobalProtect"
click menu bar item 1 of menu bar 2 -- Activates the GlobalProtect "window" in the menubar
set frontmost to true -- keep window 1 active
tell window 1
-- Click on the connect or disconnect button, depending on if they exist or not
if exists (first UI element whose title is "Connect") then
tell (first UI element whose title is "Connect") to if exists then click
else
tell (first UI element whose title is "Disconnect") to if exists then click
end if
end tell
click menu bar item 1 of menu bar 2 -- This will close the GlobalProtect "window" after clicking Connect/Disconnect. This is optional.
end tell
'
]])
end
local function switchOff()
runScript()
is_on = false
globalprotect_icon:set({
icon = { color = colors.orange },
background = { border_color = colors.orange }
})
globalprotect_bracket:set({
background = { border_color = colors.orange }
})
end
local function switchOn()
runScript()
is_on = true
globalprotect_icon:set({
icon = { color = colors.red }
})
globalprotect_bracket:set({
background = { border_color = colors.red }
})
end
local function toggleGlobalProtectConnection(env)
if is_on == true then
switchOff()
else
switchOn()
end
end
globalprotect_icon:subscribe("mouse.clicked", toggleGlobalProtectConnection) Credits to the creator of the osascript : https://gist.github.com/kaleksandrov/3cfee92845a403da995e7e44ba771183?permalink_comment_id=4416917#gistcomment-4416917 |
Beta Was this translation helpful? Give feedback.
-
Aerospace workspace application icons![]() ![]() This plugin replace the items.spaces (used for showing mission control workspaces), instead this items.workspaces shows the aerospace workspaces. supports multiple monitors
exec-on-workspace-change = [
'/bin/bash', '-c', '/opt/homebrew/bin/sketchybar --trigger aerospace_workspace_change FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE'
]
local colors = require("colors")
local settings = require("settings")
local app_icons = require("helpers.app_icons")
local sbar = require("sketchybar")
sbar.add("event", "aerospace_workspace_change")
local workspaces = {}
-- Function to execute shell commands and return the output
local function execute_command(command)
local handle = io.popen(command)
local result = handle:read("*a")
handle:close()
return result
end
local function add_workspace(monitor_id, workspace_id)
local space = sbar.add("space", "space." .. tostring(workspace_id), {
space = monitor_id,
display = monitor_id,
icon = {
font = { family = settings.font.numbers, size = 18 },
string = workspace_id,
padding_left = 15,
padding_right = 8,
color = colors.white,
highlight_color = colors.green,
},
label = {
padding_right = 20,
color = colors.grey,
highlight_color = colors.white,
font = "sketchybar-app-font:Regular:16.0",
y_offset = -1,
},
padding_right = 1,
padding_left = 1,
background = {
color = colors.bg1,
border_width = 1,
height = 26,
},
popup = { background = { border_width = 5, border_color = colors.black } },
})
workspaces[workspace_id] = space
-- Single item bracket for space items to achieve double border on highlight
local space_bracket = sbar.add("bracket", { space.name }, {
background = {
color = colors.transparent,
height = 28,
border_width = 2,
},
})
-- Padding space
sbar.add("space", "space.padding." .. tostring(workspace_id), {
space = monitor_id,
script = "",
width = settings.group_paddings,
})
space:subscribe({ "aerospace_workspace_change" }, function(env)
local selected = tonumber(env.FOCUSED_WORKSPACE) == workspace_id
space:set({
icon = { highlight = selected },
label = { highlight = selected },
background = { border_color = selected and colors.black or colors.bg2 },
})
space_bracket:set({
background = { border_color = selected and colors.orange or colors.bg2 },
})
end)
end
-- Get monitor information
local monitors = {}
local monitor_output = execute_command("aerospace list-monitors")
for line in monitor_output:gmatch("[^\r\n]+") do
local id, name = line:match("(%d+) | (.+)")
if id and name then
monitors[tonumber(id)] = name
end
end
-- Get workspaces for each monitor
for monitor_id, _ in pairs(monitors) do
local workspace_output = execute_command("aerospace list-workspaces --monitor " .. monitor_id)
for workspace_id in workspace_output:gmatch("[^\r\n]+") do
add_workspace(monitor_id, tonumber(workspace_id))
end
end
local space_window_observer = sbar.add("item", {
drawing = false,
updates = true,
})
local function set_icon_line(workspace_id)
sbar.exec(
[[aerospace list-windows --workspace ]] .. tostring(workspace_id) .. [[ | awk -F '|' '{print $2}']],
function(appNames)
local appCounts = {}
-- Split the input string by newline into individual app names
for appName in string.gmatch(appNames, "[^\r\n]+") do
-- Trim leading and trailing whitespace
appName = appName:match("^%s*(.-)%s*$")
if appCounts[appName] then
appCounts[appName] = appCounts[appName] + 1
else
appCounts[appName] = 1
end
end
local icon_line = ""
local no_app = true
for app, _ in pairs(appCounts) do
no_app = false
local lookup = app_icons[app]
local icon = ((lookup == nil) and app_icons["Default"] or lookup)
icon_line = icon_line .. icon
end
if no_app then
icon_line = " —"
end
if workspace_id == "focused" then
sbar.exec("aerospace list-workspaces --focused", function(focused_workspace)
for id in focused_workspace:gmatch("%S+") do
workspaces[tonumber(id)]:set({ label = icon_line })
end
end)
else
sbar.animate("tanh", 10, function()
workspaces[tonumber(workspace_id)]:set({ label = icon_line })
end)
end
end
)
end
space_window_observer:subscribe({ "aerospace_workspace_change" }, function(env)
set_icon_line(env.FOCUSED_WORKSPACE)
end)
space_window_observer:subscribe({ "space_windows_change" }, function()
set_icon_line("focused")
end)
-- initial run
local ok, ws = pcall(function()
return execute_command("aerospace list-workspaces --focused"):gsub("%s+", "")
end)
local focused_workspace = ok and tonumber(ws) or -1
sbar.trigger("aerospace_workspace_change", { FOCUSED_WORKSPACE = focused_workspace }) |
Beta Was this translation helpful? Give feedback.
-
Stock Widget![]() Collapsible stock widget with options to view percent change for that day, the last five days, or the past month. Refreshes every 10 minutes or when the "refresh" button is clicked. The stocks displayed can be configured using a JSON file. Clicking a stock will set it as the top option, such that it displays even when the rest of the dropdown is collapsed. Link to source code: https://github.com/TheGoldenPatrik1/sketchybar-config/blob/main/items/widgets/stocks.lua |
Beta Was this translation helpful? Give feedback.
-
A small bash-script to get notification count on latest macos: #!/bin/env sh
sql="select count(*) as cnt from record where style=1 and presented=false OR style=2;" # There is also a style=0 if that is interesting for you!
n=$(sqlite3 -readonly ~/Library/Group\ Containers/group.com.apple.usernoted/db2/db "$sql")
echo "$n" |
Beta Was this translation helpful? Give feedback.
-
Ethereum USD spot price and gas price in brackets
|
Beta Was this translation helpful? Give feedback.
-
Hello there, I want to implement system language indicator, as I have 2 langs on my mac. I need little help with this, how do I subscribe to language change event? |
Beta Was this translation helpful? Give feedback.
-
Collapsible Menu Bar ItemsThis was pain to get to work properly, particularly with the animation. Hopefully it helps someone else! PreviewScreen.Recording.2025-02-25.at.12.50.27.movGuideDependencies:
~/.config/sketchybar/items/menus.lualocal settings = require("settings")
-- Create a menu trigger item
local menu_item = sbar.add("item", "menu_trigger", {
drawing = true,
updates = true,
icon = {
font = {
size = 14.0
},
padding_left = 12,
padding_right = 12,
string = "≡",
},
label = { drawing = false }
})
menu_item:subscribe("mouse.clicked", function(env)
sbar.trigger("swap_menus_and_spaces")
end)
-- Maximum number of menu items to display
local max_items = 15
local menu_items = {}
-- Create the menu items that will appear inline
for i = 1, max_items, 1 do
local menu = sbar.add("item", "menu." .. i, {
position = "left", -- Position them on the left of the bar
drawing = false, -- Hidden by default
icon = { drawing = false },
label = {
font = {
style = settings.font.style_map["Semibold"]
},
padding_left = 8,
padding_right = 8,
},
click_script = "$CONFIG_DIR/helpers/menus/bin/menus -s " .. i,
})
menu_items[i] = menu
end
-- Menu watcher to monitor app changes
local menu_watcher = sbar.add("item", {
drawing = false,
updates = false,
})
-- Menu state variable
local menu_visible = false
-- Function to update menu contents
local function update_menus()
sbar.exec("$CONFIG_DIR/helpers/menus/bin/menus -l", function(menus)
-- Reset all menu items
for i = 1, max_items do
menu_items[i]:set({ drawing = false, width = 0 })
end
-- Update with new menu items
local id = 1
for menu in string.gmatch(menus, '[^\r\n]+') do
if id <= max_items then
menu_items[id]:set({
label = {
string = menu,
},
drawing = menu_visible,
width = menu_visible and "dynamic" or 0
})
else
break
end
id = id + 1
end
end)
end
-- Function to toggle the menu
local function toggle_menu()
-- Toggle the menu state
menu_visible = not menu_visible
if menu_visible then
-- Show menu items with animation
menu_watcher:set({ updates = true })
-- Prepare menu items but keep them hidden until animation starts
update_menus()
-- Initialize items with drawing=false and width=0
for i = 1, max_items do
local query = menu_items[i]:query()
local has_content = query.label.string ~= ""
if has_content then
-- Make sure items aren't visible at 0 width
menu_items[i]:set({
drawing = false,
width = 0,
label = {
drawing = false
}
})
end
end
-- First make them drawing=true but with label still hidden
for i = 1, max_items do
local query = menu_items[i]:query()
local has_content = query.label.string ~= ""
if has_content then
menu_items[i]:set({ drawing = true })
end
end
-- Animate the expansion
sbar.animate("tanh", 30, function()
for i = 1, max_items do
local query = menu_items[i]:query()
local is_drawing = query.geometry.drawing == "on"
if is_drawing then
-- First set the width
menu_items[i]:set({ width = "dynamic" })
-- Then make label visible
menu_items[i]:set({
label = {
drawing = true
}
})
end
end
end)
else
update_menus()
-- Hide menu items with animation
sbar.animate("tanh", 30, function()
for i = 1, max_items do
menu_items[i]:set({ width = 0 })
end
end, function()
for i = 1, max_items do
menu_items[i]:set({ drawing = false })
end
menu_watcher:set({ updates = false })
end)
end
end
-- Click to toggle menu
menu_item:subscribe("mouse.clicked", function(env)
toggle_menu()
end)
-- Subscribe to front app changes
menu_watcher:subscribe("front_app_switched", function(env)
update_menus()
end)
-- Initial update
update_menus()
return menu_watcher |
Beta Was this translation helpful? Give feedback.
-
Aerospace WorkspacesEvery other implementation of Aerospace workspaces within Sketchybar had weird issues in my experience, either they wouldn't reflect changes without switching workspaces, or wouldn't show empty workspaces after they contained applications. The one thing to note is that it handles updates by listening for workspaces changes set by Aerospace, as well as app changes. So if you move an app from workspace to another and there's another app within your current workspace, it'll immediately reflect the change as your focus will be shifted to your other app. If there isn't another app, the change will be reflected when you change workspace, or switch app focus. If you struggle to get this to work, please take a look at my complete Aerospace + Sketchybar config (the zip file appears empty, as the files are dot files): sketchybar-aerospace.zip Extract this to your home directory, then run PreviewScreen.Recording.2025-02-26.at.13.08.28.mp4GuideDependencies:
~/.config/sketchybar/items/workspaces.lualocal colors = require("colors")
local settings = require("settings")
local app_icons = require("helpers.app_icons")
local query_workspaces = "aerospace list-workspaces --all --format '%{workspace}%{monitor-appkit-nsscreen-screens-id}' --json"
-- Root is used to handle event subscriptions
local root = sbar.add("item", { drawing = false, })
local workspaces = {}
local function withWindows(f)
local open_windows = {}
-- Include the window ID in the query so we can track unique windows
local get_windows = "aerospace list-windows --monitor all --format '%{workspace}%{app-name}%{window-id}' --json"
local query_visible_workspaces =
"aerospace list-workspaces --visible --monitor all --format '%{workspace}%{monitor-appkit-nsscreen-screens-id}' --json"
local get_focus_workspaces = "aerospace list-workspaces --focused"
sbar.exec(get_windows, function(workspace_and_windows)
-- Use a set to track unique window IDs
local processed_windows = {}
for _, entry in ipairs(workspace_and_windows) do
local workspace_index = entry.workspace
local app = entry["app-name"]
local window_id = entry["window-id"]
-- Only process each window ID once
if not processed_windows[window_id] then
processed_windows[window_id] = true
if open_windows[workspace_index] == nil then
open_windows[workspace_index] = {}
end
-- Check if this app is already in the list for this workspace
local app_exists = false
for _, existing_app in ipairs(open_windows[workspace_index]) do
if existing_app == app then
app_exists = true
break
end
end
-- Only add the app if it's not already in the list
if not app_exists then
table.insert(open_windows[workspace_index], app)
end
end
end
sbar.exec(get_focus_workspaces, function(focused_workspaces)
sbar.exec(query_visible_workspaces, function(visible_workspaces)
local args = {
open_windows = open_windows,
focused_workspaces = focused_workspaces,
visible_workspaces = visible_workspaces
}
f(args)
end)
end)
end)
end
local function updateWindow(workspace_index, args)
local open_windows = args.open_windows[workspace_index]
local focused_workspaces = args.focused_workspaces
local visible_workspaces = args.visible_workspaces
if open_windows == nil then
open_windows = {}
end
local icon_line = ""
local no_app = true
for i, open_window in ipairs(open_windows) do
no_app = false
local app = open_window
local lookup = app_icons[app]
local icon = ((lookup == nil) and app_icons["Default"] or lookup)
icon_line = icon_line .. " " .. icon
end
sbar.animate("tanh", 10, function()
for i, visible_workspace in ipairs(visible_workspaces) do
if no_app and workspace_index == visible_workspace["workspace"] then
local monitor_id = visible_workspace["monitor-appkit-nsscreen-screens-id"]
icon_line = " —"
workspaces[workspace_index]:set({
drawing = true,
label = { string = icon_line },
display = monitor_id,
})
return
end
end
if no_app and workspace_index ~= focused_workspaces then
workspaces[workspace_index]:set({
drawing = false,
})
return
end
if no_app and workspace_index == focused_workspaces then
icon_line = " —"
workspaces[workspace_index]:set({
drawing = true,
label = { string = icon_line },
})
end
workspaces[workspace_index]:set({
drawing = true,
label = { string = icon_line },
})
end)
end
local function updateWindows()
withWindows(function(args)
for workspace_index, _ in pairs(workspaces) do
updateWindow(workspace_index, args)
end
end)
end
local function updateWorkspaceMonitor()
local workspace_monitor = {}
sbar.exec(query_workspaces, function(workspaces_and_monitors)
for _, entry in ipairs(workspaces_and_monitors) do
local space_index = entry.workspace
local monitor_id = math.floor(entry["monitor-appkit-nsscreen-screens-id"])
workspace_monitor[space_index] = monitor_id
end
for workspace_index, _ in pairs(workspaces) do
workspaces[workspace_index]:set({
display = workspace_monitor[workspace_index],
})
end
end)
end
sbar.exec(query_workspaces, function(workspaces_and_monitors)
for _, entry in ipairs(workspaces_and_monitors) do
local workspace_index = entry.workspace
local workspace = sbar.add("item", {
background = {
color = colors.bg1,
drawing = true,
},
click_script = "aerospace workspace " .. workspace_index,
drawing = false, -- Hide all items at first
icon = {
color = colors.with_alpha(colors.white, 0.3),
drawing = true,
font = { family = settings.font.numbers },
highlight_color = colors.white,
padding_left = 5,
padding_right = 4,
string = workspace_index
},
label = {
color = colors.with_alpha(colors.white, 0.3),
drawing = true,
font = "sketchybar-app-font:Regular:16.0",
highlight_color = colors.white,
padding_left = 2,
padding_right = 12,
y_offset = -1,
},
})
workspaces[workspace_index] = workspace
workspace:subscribe("aerospace_workspace_change", function(env)
local focused_workspace = env.FOCUSED_WORKSPACE
local is_focused = focused_workspace == workspace_index
sbar.animate("tanh", 10, function()
workspace:set({
icon = { highlight = is_focused },
label = { highlight = is_focused },
blur_radius = 30,
})
end)
end)
end
-- Initial setup
updateWindows()
updateWorkspaceMonitor()
-- Subscribe to window creation/destruction events
root:subscribe("aerospace_workspace_change", function()
updateWindows()
end)
-- Subscribe to front app changes too
root:subscribe("front_app_switched", function()
updateWindows()
end)
root:subscribe("display_change", function()
updateWorkspaceMonitor()
updateWindows()
end)
sbar.exec("aerospace list-workspaces --focused", function(focused_workspace)
local focused_workspace = focused_workspace:match("^%s*(.-)%s*$")
workspaces[focused_workspace]:set({
icon = { highlight = true },
label = { highlight = true },
})
end)
end) |
Beta Was this translation helpful? Give feedback.
-
Thank you, and special thanks to @wolveix. This is by far the best workspace switcher I’ve used. I’ll definitely be sticking with it and truly appreciate you sharing it! |
Beta Was this translation helpful? Give feedback.
-
I borrowed most of the code from @tcmmichaelb139 (Michael Bao), and added the "weather" and "network" items. My repo: https://github.com/nguyenvulong/devenv-macos |
Beta Was this translation helpful? Give feedback.
-
I have written a sketchybar plugin in rust https://github.com/xiamaz/sketchybar-aerospace-plugin, which supports showing aerospace spaces with sketchybar app icons. We use the mach header from sbarlua and do everything else directly using rust C FFI calls. It supports batching of sketchybar calls, but the slow part is actually aerospace. Currently the plugin requires my fork of the aerospace repo, but hopefully some of the changes might get merged back in. Potentially a good starting point if anyone else is interested in writing faster or more complex plugins in rust. |
Beta Was this translation helpful? Give feedback.
-
This is a thread to share the plugins you've created with the community.
Beta Was this translation helpful? Give feedback.
All reactions