diff options
author | Hunt <lizhunt@amazon.com> | 2025-06-27 14:25:22 -0700 |
---|---|---|
committer | Hunt <lizhunt@amazon.com> | 2025-06-27 14:44:54 -0700 |
commit | 0ba773cb8cb5162019d42c511f2580d601ab65d1 (patch) | |
tree | 7224f2e249df760213216a97ee73220e83a04b9f /dots/sketchybar/.config/sketchybar/items | |
parent | dccdc3326cea3ad1e951438e6d38170d84d186d8 (diff) | |
download | dotfiles-0ba773cb8cb5162019d42c511f2580d601ab65d1.tar.gz dotfiles-0ba773cb8cb5162019d42c511f2580d601ab65d1.zip |
Add sketchybar
Diffstat (limited to 'dots/sketchybar/.config/sketchybar/items')
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/apple.lua | 7 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/front_apps.lua | 71 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/init.lua | 12 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/media.lua | 118 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/menu_spaces_toggle.lua | 71 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/menus.lua | 74 | ||||
-rwxr-xr-x | dots/sketchybar/.config/sketchybar/items/menus/bin/menus | bin | 0 -> 36920 bytes | |||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/message.lua | 55 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/spaces.lua.j2 | 99 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/widgets/battery.lua | 91 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/widgets/calendar.lua | 17 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/widgets/init.lua | 4 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/widgets/volume.lua | 128 | ||||
-rw-r--r-- | dots/sketchybar/.config/sketchybar/items/widgets/wifi.lua | 261 |
14 files changed, 1008 insertions, 0 deletions
diff --git a/dots/sketchybar/.config/sketchybar/items/apple.lua b/dots/sketchybar/.config/sketchybar/items/apple.lua new file mode 100644 index 0000000..001f348 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/apple.lua @@ -0,0 +1,7 @@ +local settings = require("config.settings") + +local apple = sbar.add("item", "apple", { + icon = { string = settings.icons.text.apple }, + label = { drawing = false }, + click_script = "$CONFIG_DIR/items/menus/bin/menus -s 0" +}) diff --git a/dots/sketchybar/.config/sketchybar/items/front_apps.lua b/dots/sketchybar/.config/sketchybar/items/front_apps.lua new file mode 100644 index 0000000..dc0d606 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/front_apps.lua @@ -0,0 +1,71 @@ +local constants = require("constants") +local settings = require("config.settings") + +local frontApps = {} + +sbar.add("bracket", constants.items.FRONT_APPS, {}, { position = "left" }) + +local frontAppWatcher = sbar.add("item", { + drawing = false, + updates = true, +}) + +local function selectFocusedWindow(frontAppName) + for appName, app in pairs(frontApps) do + local isSelected = appName == frontAppName + local color = isSelected and settings.colors.orange or settings.colors.white + app:set( + { + label = { color = color }, + icon = { color = color }, + } + ) + end +end + +local function updateWindows(windows) + sbar.remove("/" .. constants.items.FRONT_APPS .. "\\.*/") + + frontApps = {} + local foundWindows = string.gmatch(windows, "[^\n]+") + for window in foundWindows do + local parsedWindow = {} + for key, value in string.gmatch(window, "(%w+)=([%w%s]+)") do + parsedWindow[key] = value + end + + local windowId = parsedWindow["id"] + local windowName = parsedWindow["name"] + local icon = settings.icons.apps[windowName] or settings.icons.apps["default"] + + frontApps[windowName] = sbar.add("item", constants.items.FRONT_APPS .. "." .. windowName, { + label = { + padding_left = 0, + string = windowName, + }, + icon = { + string = icon, + font = settings.fonts.icons(), + }, + click_script = "aerospace focus --window-id " .. windowId, + }) + + frontApps[windowName]:subscribe(constants.events.FRONT_APP_SWITCHED, function(env) + selectFocusedWindow(env.INFO) + end) + end + + sbar.exec(constants.aerospace.GET_CURRENT_WINDOW, function(frontAppName) + selectFocusedWindow(frontAppName:gsub("[\n\r]", "")) + end) +end + +local function getWindows() + sbar.exec(constants.aerospace.LIST_WINDOWS, updateWindows) +end + +frontAppWatcher:subscribe(constants.events.UPDATE_WINDOWS, function() + getWindows() +end) + +getWindows() diff --git a/dots/sketchybar/.config/sketchybar/items/init.lua b/dots/sketchybar/.config/sketchybar/items/init.lua new file mode 100644 index 0000000..30625e3 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/init.lua @@ -0,0 +1,12 @@ +-- Left items +require("items.apple") +require("items.menu_spaces_toggle") +require("items.menus") +require("items.spaces") +require("items.front_apps") + +-- Right items +require("items.message") +require("items.widgets") + +-- require("items.media") diff --git a/dots/sketchybar/.config/sketchybar/items/media.lua b/dots/sketchybar/.config/sketchybar/items/media.lua new file mode 100644 index 0000000..1d34084 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/media.lua @@ -0,0 +1,118 @@ +local colors = require("config.colors") + +local whitelist = { + ["Psst"] = true, +}; + +local media_cover = sbar.add("item", { + position = "left", + background = { + image = { + string = "media.artwork", + scale = 0.80, + }, + color = colors.transparent, + }, + label = { drawing = false }, + icon = { drawing = false }, + drawing = false, + updates = true, + popup = { + align = "center", + horizontal = true, + } +}) + +local media_artist = sbar.add("item", { + position = "left", + drawing = false, + padding_left = 3, + padding_right = 0, + width = 0, + icon = { drawing = false }, + label = { + width = 0, + font = { size = 9 }, + color = colors.with_alpha(colors.white, 0.6), + max_chars = 24, + y_offset = 6, + }, +}) + +local media_title = sbar.add("item", { + position = "left", + drawing = false, + padding_left = 3, + padding_right = 0, + icon = { drawing = false }, + label = { + font = { size = 11 }, + width = 0, + max_chars = 35, + y_offset = -5, + }, +}) + +sbar.add("item", { + position = "popup." .. media_cover.name, + icon = { string = icons.media.back }, + label = { drawing = false }, + click_script = "nowplaying-cli previous", +}) +sbar.add("item", { + position = "popup." .. media_cover.name, + icon = { string = icons.media.play_pause }, + label = { drawing = false }, + click_script = "nowplaying-cli togglePlayPause", +}) +sbar.add("item", { + position = "popup." .. media_cover.name, + icon = { string = icons.media.forward }, + label = { drawing = false }, + click_script = "nowplaying-cli next", +}) + +local interrupt = 0 +local function animate_detail(detail) + if (not detail) then interrupt = interrupt - 1 end + if interrupt > 0 and (not detail) then return end + + sbar.animate("tanh", 30, function() + media_artist:set({ label = { width = detail and "dynamic" or 0 } }) + media_title:set({ label = { width = detail and "dynamic" or 0 } }) + end) +end + +media_cover:subscribe("media_change", function(env) + if whitelist[env.INFO.app] then + local drawing = (env.INFO.state == "playing") + media_artist:set({ drawing = drawing, label = env.INFO.artist, }) + media_title:set({ drawing = drawing, label = env.INFO.title, }) + media_cover:set({ drawing = drawing }) + + if drawing then + animate_detail(true) + interrupt = interrupt + 1 + sbar.delay(5, animate_detail) + else + media_cover:set({ popup = { drawing = false } }) + end + end +end) + +media_cover:subscribe("mouse.entered", function(env) + interrupt = interrupt + 1 + animate_detail(true) +end) + +media_cover:subscribe("mouse.exited", function(env) + animate_detail(false) +end) + +media_cover:subscribe("mouse.clicked", function(env) + media_cover:set({ popup = { drawing = "toggle" } }) +end) + +media_title:subscribe("mouse.exited.global", function(env) + media_cover:set({ popup = { drawing = false } }) +end) diff --git a/dots/sketchybar/.config/sketchybar/items/menu_spaces_toggle.lua b/dots/sketchybar/.config/sketchybar/items/menu_spaces_toggle.lua new file mode 100644 index 0000000..bed73d5 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/menu_spaces_toggle.lua @@ -0,0 +1,71 @@ +local constants = require("constants") +local settings = require("config.settings") + +sbar.add("event", constants.events.SWAP_MENU_AND_SPACES) + +local function switchToggle(menuToggle) + local isShowingMenu = menuToggle:query().icon.value == settings.icons.text.switch.on + + menuToggle:set({ + icon = isShowingMenu and settings.icons.text.switch.off or settings.icons.text.switch.on, + label = isShowingMenu and "Menus" or "Spaces", + }) + + sbar.trigger(constants.events.SWAP_MENU_AND_SPACES, { isShowingMenu = isShowingMenu }) +end + +local function addToggle() + local menuToggle = sbar.add("item", constants.items.MENU_TOGGLE, { + icon = { + string = settings.icons.text.switch.on + }, + label = { + width = 0, + color = settings.colors.bg1, + string = "Spaces", + }, + background = { + color = settings.colors.with_alpha(settings.colors.dirty_white, 0.0), + } + }) + + sbar.add("item", constants.items.MENU_TOGGLE .. ".padding", { + width = settings.dimens.padding.label + }) + + menuToggle:subscribe("mouse.entered", function(env) + sbar.animate("tanh", 30, function() + menuToggle:set({ + background = { + color = { alpha = 1.0 }, + border_color = { alpha = 0.5 }, + }, + icon = { color = settings.colors.bg1 }, + label = { width = "dynamic" } + }) + end) + end) + + menuToggle:subscribe("mouse.exited", function(env) + sbar.animate("tanh", 30, function() + menuToggle:set({ + background = { + color = { alpha = 0.0 }, + border_color = { alpha = 0.0 }, + }, + icon = { color = settings.colors.white }, + label = { width = 0 } + }) + end) + end) + + menuToggle:subscribe("mouse.clicked", function(env) + switchToggle(menuToggle) + end) + + menuToggle:subscribe(constants.events.AEROSPACE_SWITCH, function(env) + switchToggle(menuToggle) + end) +end + +addToggle() diff --git a/dots/sketchybar/.config/sketchybar/items/menus.lua b/dots/sketchybar/.config/sketchybar/items/menus.lua new file mode 100644 index 0000000..674963a --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/menus.lua @@ -0,0 +1,74 @@ +local constants = require("constants") +local settings = require("config.settings") + +local maxItems <const> = 15 +local menuItems = {} +local isShowingMenu = false + +local frontAppWatcher = sbar.add("item", { + drawing = false, + updates = true, +}) + +local swapWatcher = sbar.add("item", { + drawing = false, + updates = true, +}) + +local function createPlaceholders() + for index = 1, maxItems, 1 do + local menu = sbar.add("item", constants.items.MENU .. "." .. index, { + drawing = false, + icon = { drawing = false }, + width = "dynamic", + label = { + font = { + style = index == 1 and settings.fonts.styles.bold or settings.fonts.styles.regular, + }, + }, + click_script = "$CONFIG_DIR/bridge/menus/bin/menus -s " .. index, + }) + menuItems[index] = menu + end + + sbar.add("bracket", { "/" .. constants.items.MENU .. "\\..*/" }, { + background = { + color = settings.colors.bg1, + padding_left = settings.dimens.padding.item, + padding_right = settings.dimens.padding.item, + }, + }) +end + +local function updateMenus() + sbar.set("/" .. constants.items.MENU .. "\\..*/", { drawing = false }) + + sbar.exec("$CONFIG_DIR/bridge/menus/bin/menus -l", function(menus) + local index = 1 + for menu in string.gmatch(menus, '[^\r\n]+') do + if index < maxItems then + menuItems[index]:set( + { + width = "dynamic", + label = menu, + drawing = isShowingMenu + } + ) + else + break + end + index = index + 1 + end + end) + + sbar.set(constants.items.MENU .. ".padding", { drawing = isShowingMenu }) +end + +frontAppWatcher:subscribe(constants.events.FRONT_APP_SWITCHED, updateMenus) + +swapWatcher:subscribe(constants.events.SWAP_MENU_AND_SPACES, function(env) + isShowingMenu = env.isShowingMenu == "on" + updateMenus() +end) + +createPlaceholders() diff --git a/dots/sketchybar/.config/sketchybar/items/menus/bin/menus b/dots/sketchybar/.config/sketchybar/items/menus/bin/menus Binary files differnew file mode 100755 index 0000000..4d92744 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/menus/bin/menus diff --git a/dots/sketchybar/.config/sketchybar/items/message.lua b/dots/sketchybar/.config/sketchybar/items/message.lua new file mode 100644 index 0000000..1be586a --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/message.lua @@ -0,0 +1,55 @@ +local constants = require("constants") +local settings = require("config.settings") + +local message = sbar.add("item", constants.items.MESSAGE, { + width = 0, + position = "center", + popup = { align = "center" }, + label = { + padding_left = 0, + padding_right = 0, + }, + background = { + padding_left = 0, + padding_right = 0, + } +}) + +local messagePopup = sbar.add("item", { + position = "popup." .. message.name, + width = "dynamic", + label = { + padding_right = settings.dimens.padding.label, + padding_left = settings.dimens.padding.label, + }, + icon = { + padding_left = 0, + padding_right = 0, + }, +}) + +local function hideMessage() + message:set({ popup = { drawing = false } }) +end + +local function showMessage(content, hold) + hideMessage() + + message:set({ popup = { drawing = true } }) + messagePopup:set({ label = { string = content } }) + + if hold == false then + sbar.delay(5, function() + if hold then return end + hideMessage() + end) + end +end + +message:subscribe(constants.events.SEND_MESSAGE, function(env) + local content = env.MESSAGE + local hold = env.HOLD ~= nil and env.HOLD == "true" or false + showMessage(content, hold) +end) + +message:subscribe(constants.events.HIDE_MESSAGE, hideMessage) diff --git a/dots/sketchybar/.config/sketchybar/items/spaces.lua.j2 b/dots/sketchybar/.config/sketchybar/items/spaces.lua.j2 new file mode 100644 index 0000000..6d1d6a9 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/spaces.lua.j2 @@ -0,0 +1,99 @@ +local constants = require("constants") +local settings = require("config.settings") + +local spaces = {} + +local swapWatcher = sbar.add("item", { + drawing = false, + updates = true, +}) + +local currentWorkspaceWatcher = sbar.add("item", { + drawing = false, + updates = true, +}) + +local spaceConfigs <const> = { +{% for name, ws in window_manager.workspaces.items() %} + ["{{ name }}"] = { icon = "{{ ws.icon }}", name = "{{ name }}" }, +{% endfor %} +} + +local function selectCurrentWorkspace(focusedWorkspaceName) + for sid, item in pairs(spaces) do + if item ~= nil then + local isSelected = sid == constants.items.SPACES .. "." .. focusedWorkspaceName + item:set({ + icon = { color = isSelected and settings.colors.bg1 or settings.colors.white }, + label = { color = isSelected and settings.colors.bg1 or settings.colors.white }, + background = { color = isSelected and settings.colors.white or settings.colors.bg1 }, + }) + end + end + + sbar.trigger(constants.events.UPDATE_WINDOWS) +end + +local function findAndSelectCurrentWorkspace() + sbar.exec(constants.aerospace.GET_CURRENT_WORKSPACE, function(focusedWorkspaceOutput) + local focusedWorkspaceName = focusedWorkspaceOutput:match("[^\r\n]+") + selectCurrentWorkspace(focusedWorkspaceName) + end) +end + +local function addWorkspaceItem(workspaceName) + local spaceName = constants.items.SPACES .. "." .. workspaceName + local spaceConfig = spaceConfigs[workspaceName] + + spaces[spaceName] = sbar.add("item", spaceName, { + label = { + width = 0, + padding_left = 0, + string = spaceConfig.name, + }, + icon = { + string = spaceConfig.icon or settings.icons.apps["default"], + color = settings.colors.white, + }, + background = { + color = settings.colors.bg1, + }, + click_script = "aerospace workspace " .. workspaceName, + }) + + spaces[spaceName]:subscribe("mouse.entered", function(env) + sbar.animate("tanh", 30, function() + spaces[spaceName]:set({ label = { width = "dynamic" } }) + end) + end) + + spaces[spaceName]:subscribe("mouse.exited", function(env) + sbar.animate("tanh", 30, function() + spaces[spaceName]:set({ label = { width = 0 } }) + end) + end) + + sbar.add("item", spaceName .. ".padding", { + width = settings.dimens.padding.label + }) +end + +local function createWorkspaces() + {% for name, ws in window_manager.workspaces.items() | sort(attribute='1.order') %} + addWorkspaceItem("{{ name }}") + {% endfor %} + + findAndSelectCurrentWorkspace() +end + +swapWatcher:subscribe(constants.events.SWAP_MENU_AND_SPACES, function(env) + local isShowingSpaces = env.isShowingMenu == "off" and true or false + sbar.set("/" .. constants.items.SPACES .. "\\..*/", { drawing = isShowingSpaces }) +end) + +currentWorkspaceWatcher:subscribe(constants.events.AEROSPACE_WORKSPACE_CHANGED, function(env) + selectCurrentWorkspace(env.FOCUSED_WORKSPACE) + sbar.trigger(constants.events.UPDATE_WINDOWS) +end) + +createWorkspaces() diff --git a/dots/sketchybar/.config/sketchybar/items/widgets/battery.lua b/dots/sketchybar/.config/sketchybar/items/widgets/battery.lua new file mode 100644 index 0000000..32546f0 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/widgets/battery.lua @@ -0,0 +1,91 @@ +local constants = require("constants") +local settings = require("config.settings") + +local isCharging = false + +local battery = sbar.add("item", constants.items.battery, { + position = "right", + update_freq = 60, +}) + +local batteryPopup = sbar.add("item", { + position = "popup." .. battery.name, + width = "dynamic", + label = { + padding_right = settings.dimens.padding.label, + padding_left = settings.dimens.padding.label, + }, + icon = { + padding_left = 0, + padding_right = 0, + }, +}) + +battery:subscribe({ "routine", "power_source_change", "system_woke" }, function() + sbar.exec("pmset -g batt", function(batteryInfo) + local icon = "!" + local label = "?" + + local found, _, charge = batteryInfo:find("(%d+)%%") + if found then + charge = tonumber(charge) + label = charge .. "%" + end + + local color = settings.colors.green + local charging, _, _ = batteryInfo:find("AC Power") + + isCharging = charging + + if charging then + icon = settings.icons.text.battery.charging + else + if found and charge > 80 then + icon = settings.icons.text.battery._100 + elseif found and charge > 60 then + icon = settings.icons.text.battery._75 + elseif found and charge > 40 then + icon = settings.icons.text.battery._50 + elseif found and charge > 30 then + icon = settings.icons.text.battery._50 + color = settings.colors.yellow + elseif found and charge > 20 then + icon = settings.icons.text.battery._25 + color = settings.colors.orange + else + icon = settings.icons.text.battery._0 + color = settings.colors.red + end + end + + local lead = "" + if found and charge < 10 then + lead = "0" + end + + battery:set({ + icon = { + string = icon, + color = color + }, + label = { + string = lead .. label, + padding_left = 0, + }, + }) + end) +end) + +battery:subscribe("mouse.clicked", function(env) + local drawing = battery:query().popup.drawing + + battery:set({ popup = { drawing = "toggle" } }) + + if drawing == "off" then + sbar.exec("pmset -g batt", function(batteryInfo) + local found, _, remaining = batteryInfo:find("(%d+:%d+) remaining") + local label = found and ("Time remaining: " .. remaining .. "h") or (isCharging and "Charging" or "No estimate") + batteryPopup:set({ label = label }) + end) + end +end) diff --git a/dots/sketchybar/.config/sketchybar/items/widgets/calendar.lua b/dots/sketchybar/.config/sketchybar/items/widgets/calendar.lua new file mode 100644 index 0000000..436591d --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/widgets/calendar.lua @@ -0,0 +1,17 @@ +local constants = require("constants") + +local calendar = sbar.add("item", constants.items.CALENDAR, { + position = "right", + update_freq = 1, + icon = { padding_left = 0, padding_right = 0 } +}) + +calendar:subscribe({ "forced", "routine", "system_woke" }, function(env) + calendar:set({ + label = os.date("%a %d %b, %H:%M"), + }) +end) + +calendar:subscribe("mouse.clicked", function(env) + sbar.exec("open -a 'Calendar'") +end) diff --git a/dots/sketchybar/.config/sketchybar/items/widgets/init.lua b/dots/sketchybar/.config/sketchybar/items/widgets/init.lua new file mode 100644 index 0000000..8e9631c --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/widgets/init.lua @@ -0,0 +1,4 @@ +require("items.widgets.calendar") +require("items.widgets.battery") +require("items.widgets.volume") +require("items.widgets.wifi") diff --git a/dots/sketchybar/.config/sketchybar/items/widgets/volume.lua b/dots/sketchybar/.config/sketchybar/items/widgets/volume.lua new file mode 100644 index 0000000..7a24847 --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/widgets/volume.lua @@ -0,0 +1,128 @@ +local constants = require("constants") +local settings = require("config.settings") + +local currentAudioDevice = "None" + +local volumeValue = sbar.add("item", constants.items.VOLUME .. ".value", { + position = "right", + label = { + string = "??%", + padding_left = 0, + }, +}) + +local volumeBracket = sbar.add("bracket", constants.items.VOLUME .. ".bracket", { volumeValue.name }, { + popup = { + align = "center" + }, +}) + +local volumeSlider = sbar.add("slider", constants.items.VOLUME .. ".slider", settings.dimens.graphics.popup.width, { + position = "popup." .. volumeBracket.name, + click_script = 'osascript -e "set volume output volume $PERCENTAGE"' +}) + +volumeValue:subscribe("volume_change", function(env) + local icon = settings.icons.text.volume._0 + local volume = tonumber(env.INFO) + + sbar.exec("SwitchAudioSource -t output -c", function(result) + -- local currentOutputDevice = result:sub(1, -2) + -- if currentOutputDevice == "AirPods Max" then + -- icon = "" + -- elseif currentOutputDevice == "AirPods von Longdong Silver" or currentOutputDevice == "AirPods von Anna" then + -- icon = "" + -- elseif currentOutputDevice == "Arctis Nova Pro Wireless" then + -- icon = "" + -- elseif currentOutputDevice == "Ear (2)" then + -- icon = "" + -- elseif currentOutputDevice == "iD4" then + -- icon = "" + -- else + if volume > 60 then + icon = settings.icons.text.volume._100 + elseif volume > 30 then + icon = settings.icons.text.volume._66 + elseif volume > 10 then + icon = settings.icons.text.volume._33 + elseif volume > 0 then + icon = settings.icons.text.volume._10 + end + -- end + + local lead = "" + if volume < 10 then + lead = "0" + end + + -- volumeIcon:set({ label = icon }) + volumeSlider:set({ slider = { percentage = volume } }) + + local hasVolume = volume ~= 0 + volumeValue:set({ + icon = icon, + label = { + string = hasVolume and lead .. volume .. "%" or "", + padding_right = hasVolume and 8 or 0, + }, + }) + end) +end) + +local function hideVolumeDetails() + local drawing = volumeBracket:query().popup.drawing == "on" + if not drawing then return end + volumeBracket:set({ popup = { drawing = false } }) + sbar.remove("/" .. constants.items.VOLUME .. ".device\\.*/") +end + +local function toggleVolumeDetails(env) + if env.BUTTON == "right" then + sbar.exec("open /System/Library/PreferencePanes/Sound.prefpane") + return + end + + local shouldDraw = volumeBracket:query().popup.drawing == "off" + if shouldDraw then + volumeBracket:set({ popup = { drawing = true } }) + + sbar.exec("SwitchAudioSource -t output -c", function(result) + currentAudioDevice = result:sub(1, -2) + + sbar.exec("SwitchAudioSource -a -t output", function(available) + local current = currentAudioDevice + local counter = 0 + + for device in string.gmatch(available, '[^\r\n]+') do + local color = settings.colors.grey + if current == device then + color = settings.colors.white + end + + sbar.add("item", constants.items.VOLUME .. ".device." .. counter, { + position = "popup." .. volumeBracket.name, + align = "center", + label = { string = device, color = color }, + click_script = 'SwitchAudioSource -s "' .. + device .. + '" && sketchybar --set /' .. constants.items.VOLUME .. '.device\\.*/ label.color=' .. + settings.colors.grey .. ' --set $NAME label.color=' .. settings.colors.white + + }) + counter = counter + 1 + end + end) + end) + else + hideVolumeDetails() + end +end + +local function changeVolume(env) + local delta = env.SCROLL_DELTA + sbar.exec('osascript -e "set volume output volume (output volume of (get volume settings) + ' .. delta .. ')"') +end + +volumeValue:subscribe("mouse.clicked", toggleVolumeDetails) +volumeValue:subscribe("mouse.scrolled", changeVolume) +-- volumeValue:subscribe("mouse.exited.global", hideVolumeDetails) diff --git a/dots/sketchybar/.config/sketchybar/items/widgets/wifi.lua b/dots/sketchybar/.config/sketchybar/items/widgets/wifi.lua new file mode 100644 index 0000000..551a4da --- /dev/null +++ b/dots/sketchybar/.config/sketchybar/items/widgets/wifi.lua @@ -0,0 +1,261 @@ +local constants = require("constants") +local settings = require("config.settings") + +local popupWidth <const> = settings.dimens.graphics.popup.width + 20 + +sbar.exec( + "killall network_load >/dev/null; $CONFIG_DIR/bridge/network_load/bin/network_load en0 network_update 2.0" +) + +local wifiUp = sbar.add("item", constants.items.WIFI .. ".up", { + position = "right", + width = 0, + icon = { + padding_left = 0, + padding_right = 0, + font = { + style = settings.fonts.styles.bold, + size = 10.0, + }, + string = settings.icons.text.wifi.upload, + }, + label = { + font = { + family = settings.fonts.numbers, + style = settings.fonts.styles.bold, + size = 10.0, + }, + color = settings.colors.orange, + string = "??? Bps", + }, + y_offset = 4, +}) + +local wifiDown = sbar.add("item", constants.items.WIFI .. ".down", { + position = "right", + icon = { + padding_left = 0, + padding_right = 0, + font = { + style = settings.fonts.styles.bold, + size = 10.0, + }, + string = settings.icons.text.wifi.download, + }, + label = { + font = { + family = settings.fonts.numbers, + style = settings.fonts.styles.bold, + size = 10, + }, + color = settings.colors.blue, + string = "??? Bps", + }, + y_offset = -4, +}) + +local wifi = sbar.add("item", constants.items.WIFI .. ".padding", { + position = "right", + label = { drawing = false }, + padding_right = 0, +}) + +local wifiBracket = sbar.add("bracket", constants.items.WIFI .. ".bracket", { + wifi.name, + wifiUp.name, + wifiDown.name +}, { + popup = { align = "center" } +}) + +local ssid = sbar.add("item", { + align = "center", + position = "popup." .. wifiBracket.name, + width = popupWidth, + height = 16, + icon = { + string = settings.icons.text.wifi.router, + font = { + style = settings.fonts.styles.bold + }, + }, + label = { + font = { + style = settings.fonts.styles.bold, + size = settings.dimens.text.label, + }, + max_chars = 18, + string = "????????????", + }, +}) + +local hostname = sbar.add("item", { + position = "popup." .. wifiBracket.name, + background = { + height = 16, + }, + icon = { + align = "left", + string = "Hostname:", + width = popupWidth / 2, + font = { + size = settings.dimens.text.label + }, + }, + label = { + max_chars = 20, + string = "????????????", + width = popupWidth / 2, + align = "right", + } +}) + +local ip = sbar.add("item", { + position = "popup." .. wifiBracket.name, + background = { + height = 16, + }, + icon = { + align = "left", + string = "IP:", + width = popupWidth / 2, + font = { + size = settings.dimens.text.label + }, + }, + label = { + align = "right", + string = "???.???.???.???", + width = popupWidth / 2, + } +}) + +local router = sbar.add("item", { + position = "popup." .. wifiBracket.name, + background = { + height = 16, + }, + icon = { + align = "left", + string = "Router:", + width = popupWidth / 2, + font = { + size = settings.dimens.text.label + }, + }, + label = { + align = "right", + string = "???.???.???.???", + width = popupWidth / 2, + }, +}) + +sbar.add("item", { position = "right", width = settings.dimens.padding.item }) + +wifiUp:subscribe("network_update", function(env) + local upColor = (env.upload == "000 Bps") and settings.colors.grey or settings.colors.orange + local downColor = (env.download == "000 Bps") and settings.colors.grey or settings.colors.blue + + wifiUp:set({ + icon = { color = upColor }, + label = { + string = env.upload, + color = upColor + } + }) + wifiDown:set({ + icon = { color = downColor }, + label = { + string = env.download, + color = downColor + } + }) +end) + +wifi:subscribe({ "wifi_change", "system_woke", "forced" }, function(env) + wifi:set({ + icon = { + string = settings.icons.text.wifi.disconnected, + color = settings.colors.magenta, + } + }) + + sbar.exec([[ipconfig getifaddr en0]], function(ip) + local ipConnected = not (ip == "") + + local wifiIcon + local wifiColor + + if ipConnected then + wifiIcon = settings.icons.text.wifi.connected + wifiColor = settings.colors.white + end + + wifi:set({ + icon = { + string = wifiIcon, + color = wifiColor, + } + }) + + sbar.exec([[sleep 2; scutil --nwi | grep -m1 'utun' | awk '{ print $1 }']], function(vpn) + local isVPNConnected = not (vpn == "") + + if isVPNConnected then + wifiIcon = settings.icons.text.wifi.vpn + wifiColor = settings.colors.green + end + + wifi:set({ + icon = { + string = wifiIcon, + color = wifiColor, + } + }) + end) + end) +end) + +local function hideDetails() + wifiBracket:set({ popup = { drawing = false } }) +end + +local function toggleDetails() + local shouldDrawDetails = wifiBracket:query().popup.drawing == "off" + + if shouldDrawDetails then + wifiBracket:set({ popup = { drawing = true } }) + sbar.exec("networksetup -getcomputername", function(result) + hostname:set({ label = result }) + end) + sbar.exec("ipconfig getifaddr en0", function(result) + ip:set({ label = result }) + end) + sbar.exec("ipconfig getsummary en0 | awk -F ' SSID : ' '/ SSID : / {print $2}'", function(result) + ssid:set({ label = result }) + end) + sbar.exec("networksetup -getinfo Wi-Fi | awk -F 'Router: ' '/^Router: / {print $2}'", function(result) + router:set({ label = result }) + end) + else + hideDetails() + end +end + +local function copyLabelToClipboard(env) + local label = sbar.query(env.NAME).label.value + sbar.exec("echo \"" .. label .. "\" | pbcopy") + sbar.set(env.NAME, { label = { string = settings.icons.text.clipboard, align = "center" } }) + sbar.delay(1, function() + sbar.set(env.NAME, { label = { string = label, align = "right" } }) + end) +end + +wifiUp:subscribe("mouse.clicked", toggleDetails) +wifiDown:subscribe("mouse.clicked", toggleDetails) +wifi:subscribe("mouse.clicked", toggleDetails) + +ssid:subscribe("mouse.clicked", copyLabelToClipboard) +hostname:subscribe("mouse.clicked", copyLabelToClipboard) +ip:subscribe("mouse.clicked", copyLabelToClipboard) +router:subscribe("mouse.clicked", copyLabelToClipboard) |