diff --git a/bin/presentation-mode b/bin/presentation-mode new file mode 100755 index 0000000..d9c0dd4 --- /dev/null +++ b/bin/presentation-mode @@ -0,0 +1,21 @@ +#!/bin/bash + +# This script is used to change the top and bottom padding of the outer container in the Aerospace theme. + +presentation_pixel_gaps=300 +top_normal_pixel_gaps=82 +bottom_normal_pixel_gaps=40 +terminal_font_size=18 +terminal_presentation_font_size=22 + +if [ $1 == "on" ]; then + sed -i '' "s/\(outer\.top = *\[.*\), $top_normal_pixel_gaps]/\1, $presentation_pixel_gaps]/" ~/.config/aerospace/aerospace.toml + sed -i '' "s/\(outer\.bottom = *\[.*\), $bottom_normal_pixel_gaps]/\1, $presentation_pixel_gaps]/" ~/.config/aerospace/aerospace.toml + osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/stefan.pinter/Pictures/Wallpapers/black-gray.jpg"' + aerospace reload-config +elif [ $1 == "off" ]; then + sed -i '' "s/\(outer\.top = *\[.*\), $presentation_pixel_gaps]/\1, $top_normal_pixel_gaps]/" ~/.config/aerospace/aerospace.toml + sed -i '' "s/\(outer\.bottom = *\[.*\), $presentation_pixel_gaps]/\1, $bottom_normal_pixel_gaps]/" ~/.config/aerospace/aerospace.toml + osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/bluering.png"' + aerospace reload-config +fi diff --git a/config/aerospace/aerospace.toml b/config/aerospace/aerospace.toml index 8eef6c2..03118fd 100644 --- a/config/aerospace/aerospace.toml +++ b/config/aerospace/aerospace.toml @@ -2,7 +2,6 @@ config-version = 2 after-startup-command = [ "workspace 10", - "layout h_accordion", "workspace-back-and-forth" ] @@ -11,15 +10,20 @@ enable-normalization-flatten-containers = false enable-normalization-opposite-orientation-for-nested-containers = false on-focused-monitor-changed = ['move-mouse monitor-lazy-center'] exec-on-workspace-change = ['/bin/bash', '-c', - '/run/current-system/sw/bin/sketchybar --trigger aerospace_workspace_change FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE && /etc/profiles/per-user/rayandrew/bin/aerospace-scratchpad hook pull-window $AEROSPACE_PREV_WORKSPACE $AEROSPACE_FOCUSED_WORKSPACE' + '/run/current-system/sw/bin/sketchybar --trigger aerospace_workspace_changed FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE && /etc/profiles/per-user/rayandrew/bin/aerospace-scratchpad hook pull-window $AEROSPACE_PREV_WORKSPACE $AEROSPACE_FOCUSED_WORKSPACE' +] +on-focus-changed = [ + 'move-mouse window-lazy-center', + 'exec-and-forget /bin/bash -c /run/current-system/sw/bin/sketchybar --trigger front_app_switched', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger update_windows' ] [gaps] - inner.horizontal = [{ monitor.'^built-in retina display$' = 10 }, 15] - inner.vertical = [{ monitor.'^built-in retina display$' = 10 }, 15] - outer.left = [{ monitor.'^built-in retina display$' = 5 }, 15] - outer.right = [{ monitor.'^built-in retina display$' = 5 }, 15] - outer.bottom = [{ monitor.'^built-in retina display$' = 5 }, 15] + inner.horizontal = [{ monitor.'^built-in retina display$' = 15 }, 15] + inner.vertical = [{ monitor.'^built-in retina display$' = 15 }, 15] + outer.left = [{ monitor.'^built-in retina display$' = 15 }, 15] + outer.right = [{ monitor.'^built-in retina display$' = 15 }, 15] + outer.bottom = [{ monitor.'^built-in retina display$' = 15 }, 15] outer.top = [{ monitor.'^built-in retina display$' = 15 }, 50] [mode.main.binding] @@ -41,6 +45,7 @@ exec-on-workspace-change = ['/bin/bash', '-c', alt-f = 'fullscreen' alt-s = 'layout v_accordion' + alt-t = 'layout h_accordion' alt-e = 'layout tiles horizontal vertical' alt-space = 'layout floating tiling' @@ -66,9 +71,14 @@ exec-on-workspace-change = ['/bin/bash', '-c', alt-shift-9 = 'move-node-to-workspace 9' alt-shift-0 = 'move-node-to-workspace 10' - alt-shift-semicolon = 'mode service' - alt-r = 'mode resize' - + alt-shift-semicolon = [ + 'mode service', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger send_message MESSAGE="SERVICE MODE" HOLD="true"' + ] + alt-r = [ + 'mode resize', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger send_message MESSAGE="RESIZE MODE" HOLD="true"' + ] cmd-ctrl-1 = "exec-and-forget aerospace-scratchpad show Finder" @@ -77,11 +87,22 @@ exec-on-workspace-change = ['/bin/bash', '-c', j = 'resize height +50' k = 'resize height -50' l = 'resize width +50' - enter = 'mode main' - esc = 'mode main' + esc = [ + 'mode main', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger hide_message' + ] + enter = [ + 'mode main', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger hide_message' + ] [mode.service.binding] - c = ['reload-config', 'mode main'] + esc = [ + 'reload-config', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger hide_message', + 'exec-and-forget /run/current-system/sw/bin/sketchybar --reload', + 'mode main', + ] r = ['flatten-workspace-tree', 'mode main'] f = ['layout floating tiling', 'mode main'] backspace = ['close-all-windows-but-current', 'mode main'] @@ -102,3 +123,19 @@ exec-on-workspace-change = ['/bin/bash', '-c', [[on-window-detected]] if.app-id = 'com.1password.1password' run = ['layout floating'] + +[[on-window-detected]] + if.app-id = 'com.spotify.client' + run = ['move-node-to-workspace 7'] + +[[on-window-detected]] + if.app-id = 'com.apple.mail' + run = ['move-node-to-workspace 8'] + +[[on-window-detected]] + if.app-id = 'com.microsoft.teams2' + run = ['move-node-to-workspace 9'] + +[[on-window-detected]] + if.app-id = 'com.tinyspeck.slackmacgap' + run = ['move-node-to-workspace 9'] diff --git a/config/sketchybar/.luarc.json b/config/old_sketchybar/.luarc.json similarity index 100% rename from config/sketchybar/.luarc.json rename to config/old_sketchybar/.luarc.json diff --git a/config/sketchybar/app_icons.lua b/config/old_sketchybar/app_icons.lua similarity index 100% rename from config/sketchybar/app_icons.lua rename to config/old_sketchybar/app_icons.lua diff --git a/config/old_sketchybar/bar.lua b/config/old_sketchybar/bar.lua new file mode 100644 index 0000000..3ce9910 --- /dev/null +++ b/config/old_sketchybar/bar.lua @@ -0,0 +1,23 @@ +#!/usr/bin/env lua + +local colors = require 'colors' + +local bar_height = 35 + +sbar.bar { + blur_radius = 20, + border_color = colors.bar.border, + border_width = 2, + color = colors.bar.bg, + corner_radius = 5, + height = bar_height, + margin = 10, + notch_width = 0, + padding_left = 10, + padding_right = 10, + position = 'top', + shadow = true, + sticky = true, + topmost = false, + y_offset = 2, +} diff --git a/config/sketchybar/colors.lua b/config/old_sketchybar/colors.lua similarity index 100% rename from config/sketchybar/colors.lua rename to config/old_sketchybar/colors.lua diff --git a/config/sketchybar/icons.lua b/config/old_sketchybar/icons.lua similarity index 100% rename from config/sketchybar/icons.lua rename to config/old_sketchybar/icons.lua diff --git a/config/old_sketchybar/init.lua b/config/old_sketchybar/init.lua new file mode 100644 index 0000000..91aec1e --- /dev/null +++ b/config/old_sketchybar/init.lua @@ -0,0 +1,56 @@ +#!/usr/bin/env lua + +local colors = require 'colors' +local settings = require 'settings' + +sbar.default { + updates = 'when_shown', + icon = { + font = { + family = settings.font.text, + style = 'Bold', + size = 13.0, + }, + color = colors.fg, + padding_left = settings.paddings, + padding_right = settings.paddings, + background = { image = { corner_radius = 9 } }, + }, + label = { + font = { + family = settings.font.text, + style = 'Semibold', + size = 13.0, + }, + color = colors.fg, + padding_left = settings.paddings, + padding_right = settings.paddings, + }, + background = { + height = 30, + corner_radius = 12, + border_width = 1, + -- border_color = colors.bar.border, + image = { + corner_radius = 8, + -- border_color = colors.grey, + border_width = 1, + }, + }, + popup = { + background = { + border_width = 1, + corner_radius = 8, + border_color = colors.popup.border, + color = colors.popup.bg, + shadow = { drawing = true }, + }, + blur_radius = 20, + }, + padding_left = 5, + padding_right = 5, + scroll_texts = true, +} + +require 'bar' +require 'items' diff --git a/config/sketchybar/items/aerospace.lua b/config/old_sketchybar/items/aerospace.lua similarity index 100% rename from config/sketchybar/items/aerospace.lua rename to config/old_sketchybar/items/aerospace.lua diff --git a/config/old_sketchybar/items/apple.lua b/config/old_sketchybar/items/apple.lua new file mode 100644 index 0000000..82cbde2 --- /dev/null +++ b/config/old_sketchybar/items/apple.lua @@ -0,0 +1,37 @@ +local colors = require 'colors' +local icons = require 'icons' +local settings = require 'settings' + +-- Padding item required because of bracket +sbar.add('item', { width = 5 }) + +local apple = sbar.add('item', { + icon = { + font = { size = 16.0 }, + string = icons.apple, + padding_right = settings.paddings, + padding_left = 0, + color = colors.fg, + }, + label = { drawing = false }, + background = { + color = colors.bar.bg, + -- border_color = colors.black, + -- border_width = 1 + }, + padding_left = 1, + padding_right = 1, + click_script = 'sk-menus -s 0', +}) + +-- Double border for apple using a single item bracket +-- sbar.add("bracket", { apple.name }, { +-- background = { +-- color = colors.transparent, +-- height = 30, +-- -- border_color = colors.grey, +-- } +-- }) + +-- Padding item required because of bracket +sbar.add('item', { width = 7 }) diff --git a/config/sketchybar/items/battery.lua b/config/old_sketchybar/items/battery.lua similarity index 100% rename from config/sketchybar/items/battery.lua rename to config/old_sketchybar/items/battery.lua diff --git a/config/sketchybar/items/cal.lua b/config/old_sketchybar/items/cal.lua similarity index 100% rename from config/sketchybar/items/cal.lua rename to config/old_sketchybar/items/cal.lua diff --git a/config/sketchybar/items/cpu.lua b/config/old_sketchybar/items/cpu.lua similarity index 100% rename from config/sketchybar/items/cpu.lua rename to config/old_sketchybar/items/cpu.lua diff --git a/config/sketchybar/items/front_app.lua b/config/old_sketchybar/items/front_app.lua similarity index 100% rename from config/sketchybar/items/front_app.lua rename to config/old_sketchybar/items/front_app.lua diff --git a/config/old_sketchybar/items/init.lua b/config/old_sketchybar/items/init.lua new file mode 100644 index 0000000..3c0fca2 --- /dev/null +++ b/config/old_sketchybar/items/init.lua @@ -0,0 +1,34 @@ +local function file_exists(path) + local f = io.open(path, 'r') + if f then + f:close() + return true + end + return false +end + +local function load_module_if_program_exists(module_name, binary_path) + if file_exists(binary_path) then + print('Loading ' .. module_name .. ' (found at ' .. binary_path .. ')') + local ok, err = pcall(require, module_name) + if not ok then + print('ERROR loading ' .. module_name .. ' module: ' .. tostring(err)) + else + print('Successfully loaded ' .. module_name) + end + else + print('Skipping ' .. module_name .. ' (binary not found at ' .. binary_path .. ')') + end +end + +require 'items.apple' +-- require 'items.aerospace' +load_module_if_program_exists('items.aerospace', '/opt/homebrew/bin/aerospace') +load_module_if_program_exists('items.yabai', '/etc/profiles/per-user/rayandrew/bin/yabai') +require 'items.front_app' +require 'items.menu' +require 'items.battery' +require 'items.cal' +require 'items.volume' +require 'items.cpu' +require 'items.wifi' diff --git a/config/sketchybar/items/menu.lua b/config/old_sketchybar/items/menu.lua similarity index 100% rename from config/sketchybar/items/menu.lua rename to config/old_sketchybar/items/menu.lua diff --git a/config/sketchybar/items/volume.lua b/config/old_sketchybar/items/volume.lua similarity index 100% rename from config/sketchybar/items/volume.lua rename to config/old_sketchybar/items/volume.lua diff --git a/config/sketchybar/items/wifi.lua b/config/old_sketchybar/items/wifi.lua similarity index 100% rename from config/sketchybar/items/wifi.lua rename to config/old_sketchybar/items/wifi.lua diff --git a/config/sketchybar/items/yabai.lua b/config/old_sketchybar/items/yabai.lua similarity index 100% rename from config/sketchybar/items/yabai.lua rename to config/old_sketchybar/items/yabai.lua diff --git a/config/sketchybar/settings.lua b/config/old_sketchybar/settings.lua similarity index 100% rename from config/sketchybar/settings.lua rename to config/old_sketchybar/settings.lua diff --git a/config/sketchybar/utils.lua b/config/old_sketchybar/utils.lua similarity index 100% rename from config/sketchybar/utils.lua rename to config/old_sketchybar/utils.lua diff --git a/config/sketchybar/README.md b/config/sketchybar/README.md new file mode 100644 index 0000000..a30e333 --- /dev/null +++ b/config/sketchybar/README.md @@ -0,0 +1 @@ +Shamelessly copied from https://github.com/agenttank/dotfiles_macos/tree/1feca82518312cd8c4a784032471fedfa895989d diff --git a/config/sketchybar/bar.lua b/config/sketchybar/bar.lua index 3ce9910..6aea5b2 100644 --- a/config/sketchybar/bar.lua +++ b/config/sketchybar/bar.lua @@ -1,23 +1,15 @@ -#!/usr/bin/env lua - -local colors = require 'colors' - -local bar_height = 35 +local settings = require 'config.settings' sbar.bar { - blur_radius = 20, - border_color = colors.bar.border, - border_width = 2, - color = colors.bar.bg, - corner_radius = 5, - height = bar_height, - margin = 10, - notch_width = 0, - padding_left = 10, - padding_right = 10, - position = 'top', - shadow = true, - sticky = true, - topmost = false, - y_offset = 2, + topmost = 'window', + height = settings.dimens.graphics.bar.height, + color = settings.colors.bar.transparent, + padding_right = settings.dimens.padding.right, + padding = settings.dimens.padding.bar, + padding_left = settings.dimens.padding.left, + margin = settings.dimens.padding.bar, + corner_radius = settings.dimens.graphics.background.corner_radius, + y_offset = settings.dimens.graphics.bar.offset, + -- blur_radius = settings.dimens.graphics.blur_radius, + border_width = 0, } diff --git a/config/sketchybar/config/colors.lua b/config/sketchybar/config/colors.lua new file mode 100644 index 0000000..9029d24 --- /dev/null +++ b/config/sketchybar/config/colors.lua @@ -0,0 +1,38 @@ +local colors = { + black = 0xff181819, + white = 0xfff8f8f2, + red = 0xf1FD6592, + green = 0xff007692, + blue = 0xff5199ba, + yellow = 0xffffff81, + orange = 0xfff4c07b, + magenta = 0xd3fc7ebd, + purple = 0xff796fa9, + other_purple = 0xff302c45, + cyan = 0xff7bf2de, + grey = 0xff7f8490, + dirty_white = 0xc8cad3f5, + dark_grey = 0xff2b2736, + transparent = 0x00000000, + bar = { + bg = 0xf1151320, + border = 0xff2c2e34, + }, + popup = { + bg = 0xf1151320, + border = 0xff2c2e34, + }, + slider = { + bg = 0xf1151320, + border = 0xff2c2e34, + }, + bg1 = 0xd322212c, + bg2 = 0xff302c45, + + with_alpha = function(color, alpha) + if alpha > 1.0 or alpha < 0.0 then return color end + return (color & 0x00ffffff) | (math.floor(alpha * 255.0) << 24) + end, +} + +return colors diff --git a/config/sketchybar/config/dimens.lua b/config/sketchybar/config/dimens.lua new file mode 100644 index 0000000..8eb216b --- /dev/null +++ b/config/sketchybar/config/dimens.lua @@ -0,0 +1,40 @@ +local padding = { + background = 8, + icon = 10, + label = 8, + bar = 10, + left = 12, + right = 12, + item = 18, + popup = 8, +} + +local graphics = { + bar = { + height = 30, + offset = 8, + }, + background = { + height = 24, + corner_radius = 9, + }, + slider = { + height = 20, + }, + popup = { + width = 200, + large_width = 300, + }, + blur_radius = 30, +} + +local text = { + icon = 16.0, + label = 14.0, +} + +return { + padding = padding, + graphics = graphics, + text = text, +} diff --git a/config/sketchybar/config/fonts.lua b/config/sketchybar/config/fonts.lua new file mode 100644 index 0000000..245ba6f --- /dev/null +++ b/config/sketchybar/config/fonts.lua @@ -0,0 +1,14 @@ +local dimens = require 'config.dimens' + +return { + text = 'SpaceMono Nerd Font', + numbers = 'SpaceMono Nerd Font', + icons = function(size) + local font = 'sketchybar-app-font:Regular' + return size and font .. ':' .. size or font .. ':' .. dimens.text.icon + end, + styles = { + regular = 'Regular', + bold = 'Bold', + }, +} diff --git a/config/sketchybar/config/icons.lua b/config/sketchybar/config/icons.lua new file mode 100644 index 0000000..1589918 --- /dev/null +++ b/config/sketchybar/config/icons.lua @@ -0,0 +1,331 @@ +local apps = { + ['Live'] = ':ableton:', + ['Adobe Bridge 2024'] = ':adobe_bridge:', + ['Affinity Designer'] = ':affinity_designer:', + ['Affinity Designer 2'] = ':affinity_designer_2:', + ['Affinity Photo'] = ':affinity_photo:', + ['Affinity Photo 2'] = ':affinity_photo_2:', + ['Affinity Publisher'] = ':affinity_publisher:', + ['Affinity Publisher 2'] = ':affinity_publisher_2:', + ['Airmail'] = ':airmail:', + ['Alacritty'] = ':alacritty:', + ['Alfred Preferences'] = ':alfred:', + ['Android Messages'] = ':android_messages:', + ['Android Studio'] = ':android_studio:', + ['Anytype'] = ':anytype:', + ['App Eraser'] = ':app_eraser:', + ['App Store'] = ':app_store:', + ['Arc'] = ':arc:', + ['Atom'] = ':atom:', + ['Audacity'] = ':audacity:', + ['Bambu Studio'] = ':bambu_studio:', + ['MoneyMoney'] = ':bank:', + ['Bear'] = ':bear:', + ['BetterTouchTool'] = ':bettertouchtool:', + ['Bilibili'] = ':bilibili:', + ['哔哩哔哩'] = ':bilibili:', + ['Bitwarden'] = ':bit_warden:', + ['Blender'] = ':blender:', + ['BluOS Controller'] = ':bluos_controller:', + ['Calibre'] = ':book:', + ['Brave Browser'] = ':brave_browser:', + ['Calculator'] = ':calculator:', + ['Soulver 3'] = ':calculator:', + ['Calculette'] = ':calculator:', + ['Calendar'] = ':calendar:', + ['日历'] = ':calendar:', + ['Fantastical'] = ':calendar:', + ['Cron'] = ':calendar:', + ['Amie'] = ':calendar:', + ['Calendrier'] = ':calendar:', + ['Notion Calendar'] = ':calendar:', + ['Caprine'] = ':caprine:', + ['Citrix Workspace'] = ':citrix:', + ['Citrix Viewer'] = ':citrix:', + ['ClickUp'] = ':click_up:', + ['Code'] = ':code:', + ['Code - Insiders'] = ':code:', + ['Color Picker'] = ':color_picker:', + ['数码测色计'] = ':color_picker:', + ['CotEditor'] = ':coteditor:', + ['Cypress'] = ':cypress:', + ['DataGrip'] = ':datagrip:', + ['DataSpell'] = ':dataspell:', + ['DaVinci Resolve'] = ':davinciresolve:', + ['Default'] = ':default:', + ['CleanMyMac X'] = ':desktop:', + ['DEVONthink 3'] = ':devonthink3:', + ['DingTalk'] = ':dingtalk:', + ['钉钉'] = ':dingtalk:', + ['阿里钉'] = ':dingtalk:', + ['Discord'] = ':discord:', + ['Discord Canary'] = ':discord:', + ['Discord PTB'] = ':discord:', + ['Docker'] = ':docker:', + ['Docker Desktop'] = ':docker:', + ['GrandTotal'] = ':dollar:', + ['Receipts'] = ':dollar:', + ['Double Commander'] = ':doublecmd:', + ['Drafts'] = ':drafts:', + ['Dropbox'] = ':dropbox:', + ['Element'] = ':element:', + ['Emacs'] = ':emacs:', + ['Evernote Legacy'] = ':evernote_legacy:', + ['FaceTime'] = ':face_time:', + ['FaceTime 通话'] = ':face_time:', + ['Figma'] = ':figma:', + ['Final Cut Pro'] = ':final_cut_pro:', + ['Finder'] = ':finder:', + ['访达'] = ':finder:', + ['Firefox'] = ':firefox:', + ['Firefox Developer Edition'] = ':firefox_developer_edition:', + ['Firefox Nightly'] = ':firefox_developer_edition:', + ['Folx'] = ':folx:', + ['Fusion'] = ':fusion:', + ['System Preferences'] = ':gear:', + ['System Settings'] = ':gear:', + ['Systemeinstellungen'] = ':gear:', + ['系统设置'] = ':gear:', + ['Réglages Système'] = ':gear:', + ['GitHub Desktop'] = ':git_hub:', + ['Godot'] = ':godot:', + ['GoLand'] = ':goland:', + ['Chromium'] = ':google_chrome:', + ['Google Chrome'] = ':google_chrome:', + ['Google Chrome Canary'] = ':google_chrome:', + ['Grammarly Editor'] = ':grammarly:', + ['Home Assistant'] = ':home_assistant:', + ['Hyper'] = ':hyper:', + ['IntelliJ IDEA'] = ':idea:', + ['Inkdrop'] = ':inkdrop:', + ['Inkscape'] = ':inkscape:', + ['Insomnia'] = ':insomnia:', + ['Iris'] = ':iris:', + ['iTerm'] = ':iterm:', + ['iTerm2'] = ':iterm:', + ['Jellyfin Media Player'] = ':jellyfin:', + ['Joplin'] = ':joplin:', + ['카카오톡'] = ':kakaotalk:', + ['KakaoTalk'] = ':kakaotalk:', + ['Kakoune'] = ':kakoune:', + ['KeePassXC'] = ':kee_pass_x_c:', + ['Secrets'] = ':one_password:', + ['Keyboard Maestro'] = ':keyboard_maestro:', + ['Keynote'] = ':keynote:', + ['Keynote 讲演'] = ':keynote:', + ['kitty'] = ':kitty:', + ['League of Legends'] = ':league_of_legends:', + ['LibreWolf'] = ':libre_wolf:', + ['Adobe Lightroom'] = ':lightroom:', + ['Lightroom Classic'] = ':lightroomclassic:', + ['LINE'] = ':line:', + ['Linear'] = ':linear:', + ['LM Studio'] = ':lm_studio:', + ['LocalSend'] = ':localsend:', + ['Logic Pro'] = ':logicpro:', + ['Logseq'] = ':logseq:', + ['Canary Mail'] = ':mail:', + ['HEY'] = ':mail:', + ['Mail'] = ':mail:', + ['Mailspring'] = ':mail:', + ['MailMate'] = ':mail:', + ['Superhuman'] = ':mail:', + ['邮件'] = ':mail:', + ['MAMP'] = ':mamp:', + ['MAMP PRO'] = ':mamp:', + ['Maps'] = ':maps:', + ['Google Maps'] = ':maps:', + ['Matlab'] = ':matlab:', + ['Mattermost'] = ':mattermost:', + ['Messages'] = ':messages:', + ['信息'] = ':messages:', + ['Nachrichten'] = ':messages:', + ['Messenger'] = ':messenger:', + ['Microsoft Edge'] = ':microsoft_edge:', + ['Microsoft Excel'] = ':microsoft_excel:', + ['Microsoft Outlook'] = ':microsoft_outlook:', + ['Microsoft PowerPoint'] = ':microsoft_power_point:', + ['Microsoft Remote Desktop'] = ':microsoft_remote_desktop:', + ['Microsoft Teams'] = ':microsoft_teams:', + ['Microsoft Teams (work or school)'] = ':microsoft_teams:', + ['Microsoft Word'] = ':microsoft_word:', + ['Min'] = ':min_browser:', + ['Miro'] = ':miro:', + ['MongoDB Compass'] = ':mongodb:', + ['mpv'] = ':mpv:', + ['Mullvad Browser'] = ':mullvad_browser:', + ['Music'] = ':music:', + ['音乐'] = ':music:', + ['Musique'] = ':music:', + ['Neovide'] = ':neovide:', + ['neovide'] = ':neovide:', + ['Neovim'] = ':neovim:', + ['neovim'] = ':neovim:', + ['nvim'] = ':neovim:', + ['网易云音乐'] = ':netease_music:', + ['Noodl'] = ':noodl:', + ['Noodl Editor'] = ':noodl:', + ['NordVPN'] = ':nord_vpn:', + ['Notability'] = ':notability:', + ['Notes'] = ':notes:', + ['Notizen'] = ':notes:', + ['备忘录'] = ':notes:', + ['Notion'] = ':notion:', + ['Nova'] = ':nova:', + ['Numbers'] = ':numbers:', + ['Numbers 表格'] = ':numbers:', + ['Obsidian'] = ':obsidian:', + ['OBS'] = ':obsstudio:', + ['OmniFocus'] = ':omni_focus:', + ['1Password'] = ':one_password:', + ['ChatGPT'] = ':openai:', + ['OpenVPN Connect'] = ':openvpn_connect:', + ['Opera'] = ':opera:', + ['OrcaSlicer'] = ':orcaslicer:', + ['Orion'] = ':orion:', + ['Orion RC'] = ':orion:', + ['Pages'] = ':pages:', + ['Pages 文稿'] = ':pages:', + ['Parallels Desktop'] = ':parallels:', + ['Parsec'] = ':parsec:', + ['Preview'] = ':pdf:', + ['预览'] = ':pdf:', + ['Skim'] = ':pdf:', + ['zathura'] = ':pdf:', + ['Aperçu'] = ':pdf:', + ['PDF Expert'] = ':pdf_expert:', + ['Adobe Photoshop'] = ':photoshop:', + ['Pi-hole Remote'] = ':pihole:', + ['Pine'] = ':pine:', + ['Podcasts'] = ':podcasts:', + ['播客'] = ':podcasts:', + ['PomoDone App'] = ':pomodone:', + ['Postman'] = ':postman:', + ['PrusaSlicer'] = ':prusaslicer:', + ['SuperSlicer'] = ':prusaslicer:', + ['PyCharm'] = ':pycharm:', + ['QQ'] = ':qq:', + ['QQ音乐'] = ':qqmusic:', + ['QQMusic'] = ':qqmusic:', + ['Quantumult X'] = ':quantumult_x:', + ['qutebrowser'] = ':qute_browser:', + ['Raindrop.io'] = ':raindrop_io:', + ['Reeder'] = ':reeder5:', + ['Reminders'] = ':reminders:', + ['提醒事项'] = ':reminders:', + ['Rappels'] = ':reminders:', + ['Replit'] = ':replit:', + ['Rider'] = ':rider:', + ['JetBrains Rider'] = ':rider:', + ['Safari'] = ':safari:', + ['Safari浏览器'] = ':safari:', + ['Safari Technology Preview'] = ':safari:', + ['Sequel Ace'] = ':sequel_ace:', + ['Sequel Pro'] = ':sequel_pro:', + ['Setapp'] = ':setapp:', + ['SF Symbols'] = ':sf_symbols:', + ['Signal'] = ':signal:', + ['Sketch'] = ':sketch:', + ['Skype'] = ':skype:', + ['Slack'] = ':slack:', + ['Spark'] = ':spark:', + ['Spotify'] = ':spotify:', + ['Spotlight'] = ':spotlight:', + ['Sublime Text'] = ':sublime_text:', + ['Tana'] = ':tana:', + ['TeamSpeak 3'] = ':team_speak:', + ['Telegram'] = ':telegram:', + ['Terminal'] = ':terminal:', + ['终端'] = ':terminal:', + ['Typora'] = ':text:', + ['Microsoft To Do'] = ':things:', + ['Things'] = ':things:', + ['Thunderbird'] = ':thunderbird:', + ['TickTick'] = ':tick_tick:', + ['TIDAL'] = ':tidal:', + ['Tiny RDM'] = ':tinyrdm:', + ['Todoist'] = ':todoist:', + ['Toggl Track'] = ':toggl_track:', + ['Tor Browser'] = ':tor_browser:', + ['Tower'] = ':tower:', + ['Transmit'] = ':transmit:', + ['Trello'] = ':trello:', + ['Tweetbot'] = ':twitter:', + ['Twitter'] = ':twitter:', + ['MacVim'] = ':vim:', + ['Vim'] = ':vim:', + ['VimR'] = ':vim:', + ['Vivaldi'] = ':vivaldi:', + ['VLC'] = ':vlc:', + ['VMware Fusion'] = ':vmware_fusion:', + ['VSCodium'] = ':vscodium:', + ['Warp'] = ':warp:', + ['WebStorm'] = ':web_storm:', + ['微信'] = ':wechat:', + ['WeChat'] = ':wechat:', + ['企业微信'] = ':wecom:', + ['WeCom'] = ':wecom:', + ['WezTerm'] = ':wezterm:', + ['WhatsApp'] = ':whats_app:', + ['‎WhatsApp'] = ':whats_app:', + ['Xcode'] = ':xcode:', + ['Яндекс Музыка'] = ':yandex_music:', + ['Yuque'] = ':yuque:', + ['语雀'] = ':yuque:', + ['Zed'] = ':zed:', + ['Zeplin'] = ':zeplin:', + ['zoom.us'] = ':zoom:', + ['Zotero'] = ':zotero:', + ['Zulip'] = ':zulip:', + ['default'] = ':default:', +} + +local text = { + nerdfont = { + plus = '', + loading = '', + apple = '', + gear = '', + cpu = '', + clipboard = '󰅇', + switch = { + on = '󱨥', + off = '󱨦', + }, + volume = { + _100 = '', + _66 = '', + _33 = '', + _10 = '', + _0 = '', + }, + battery = { + _100 = '', + _75 = '', + _50 = '', + _25 = '', + _0 = '', + charging = '', + }, + wifi = { + upload = '', + download = '', + connected = '󰖩', + disconnected = '󰖪', + router = '󰑩', + }, + media = { + back = '', + forward = '', + play_pause = '', + }, + slider = { + knob = '', + }, + }, +} + +return { + text = text.nerdfont, + apps = apps, +} diff --git a/config/sketchybar/config/init.lua b/config/sketchybar/config/init.lua new file mode 100644 index 0000000..1318605 --- /dev/null +++ b/config/sketchybar/config/init.lua @@ -0,0 +1 @@ +return require 'config.settings' diff --git a/config/sketchybar/config/settings.lua b/config/sketchybar/config/settings.lua new file mode 100644 index 0000000..be373ac --- /dev/null +++ b/config/sketchybar/config/settings.lua @@ -0,0 +1,11 @@ +local colors = require 'config.colors' +local fonts = require 'config.fonts' +local icons = require 'config.icons' +local dimens = require 'config.dimens' + +return { + fonts = fonts, + dimens = dimens, + colors = colors, + icons = icons, +} diff --git a/config/sketchybar/constants.lua b/config/sketchybar/constants.lua new file mode 100644 index 0000000..17c2bc2 --- /dev/null +++ b/config/sketchybar/constants.lua @@ -0,0 +1,37 @@ +local events = { + AEROSPACE_WORKSPACE_CHANGED = 'aerospace_workspace_changed', + AEROSPACE_SWITCH = 'aerospace_switch', + SWAP_MENU_AND_SPACES = 'swap_menu_and_spaces', + FRONT_APP_SWITCHED = 'front_app_switched', + UPDATE_WINDOWS = 'update_windows', + SEND_MESSAGE = 'send_message', + HIDE_MESSAGE = 'hide_message', +} + +local items = { + SPACES = 'workspaces', + MENU = 'menu', + MENU_TOGGLE = 'menu_toggle', + FRONT_APPS = 'front_apps', + MESSAGE = 'message', + VOLUME = 'widgets.volume', + WIFI = 'widgets.wifi', + BATTERY = 'widgets.battery', + CALENDAR = 'widgets.calendar', +} + +local aerospace_cmd = '/opt/homebrew/bin/aerospace' + +local aerospace = { + LIST_ALL_WORKSPACES = aerospace_cmd .. ' list-workspaces --all', + GET_CURRENT_WORKSPACE = aerospace_cmd .. ' list-workspaces --focused', + LIST_WINDOWS = aerospace_cmd .. ' list-windows --workspace focused --format "id=%{window-id}, name=%{app-name}"', + GET_CURRENT_WINDOW = aerospace_cmd .. ' list-windows --focused --format %{app-name}', +} + +return { + items = items, + events = events, + aerospace_cmd = aerospace_cmd, + aerospace = aerospace, +} diff --git a/config/sketchybar/default.lua b/config/sketchybar/default.lua new file mode 100644 index 0000000..db56565 --- /dev/null +++ b/config/sketchybar/default.lua @@ -0,0 +1,66 @@ +local settings = require 'config.settings' + +sbar.default { + updates = 'when_shown', + icon = { + font = { + family = settings.fonts.text, + style = settings.fonts.styles.regular, + size = settings.dimens.text.icon, + }, + color = settings.colors.white, + padding_left = settings.dimens.padding.icon, + padding_right = settings.dimens.padding.icon, + }, + label = { + font = { + family = settings.fonts.text, + style = settings.fonts.styles.regular, + size = settings.dimens.text.label, + }, + color = settings.colors.white, + padding_left = settings.dimens.padding.label, + padding_right = settings.dimens.padding.label, + }, + background = { + height = settings.dimens.graphics.background.height, + corner_radius = settings.dimens.graphics.background.corner_radius, + border_width = 0, + image = { + corner_radius = settings.dimens.graphics.background.corner_radius, + }, + }, + popup = { + y_offset = settings.dimens.padding.popup, + align = 'center', + background = { + border_width = 0, + corner_radius = settings.dimens.graphics.background.corner_radius, + color = settings.colors.popup.bg, + shadow = { drawing = true }, + padding_left = settings.dimens.padding.icon, + padding_right = settings.dimens.padding.icon, + }, + blur_radius = settings.dimens.graphics.blur_radius, + }, + slider = { + highlight_color = settings.colors.orange, + background = { + height = settings.dimens.graphics.slider.height, + corner_radius = settings.dimens.graphics.background.corner_radius, + color = settings.colors.slider.bg, + border_color = settings.colors.slider.border, + border_width = 1, + }, + knob = { + font = { + family = settings.fonts.text, + style = settings.fonts.styles.regular, + size = 32, + }, + string = settings.icons.text.slider.knob, + drawing = false, + }, + }, + scroll_texts = true, +} diff --git a/config/sketchybar/init.lua b/config/sketchybar/init.lua index 91aec1e..c5d5c6f 100644 --- a/config/sketchybar/init.lua +++ b/config/sketchybar/init.lua @@ -1,56 +1,13 @@ -#!/usr/bin/env lua +sbar = require 'sketchybar' -local colors = require 'colors' -local settings = require 'settings' - -sbar.default { - updates = 'when_shown', - icon = { - font = { - family = settings.font.text, - style = 'Bold', - size = 13.0, - }, - color = colors.fg, - padding_left = settings.paddings, - padding_right = settings.paddings, - background = { image = { corner_radius = 9 } }, - }, - label = { - font = { - family = settings.font.text, - style = 'Semibold', - size = 13.0, - }, - color = colors.fg, - padding_left = settings.paddings, - padding_right = settings.paddings, - }, - background = { - height = 30, - corner_radius = 12, - border_width = 1, - -- border_color = colors.bar.border, - image = { - corner_radius = 8, - -- border_color = colors.grey, - border_width = 1, - }, - }, - popup = { - background = { - border_width = 1, - corner_radius = 8, - border_color = colors.popup.border, - color = colors.popup.bg, - shadow = { drawing = true }, - }, - blur_radius = 20, - }, - padding_left = 5, - padding_right = 5, - scroll_texts = true, -} +sbar.begin_config() +sbar.hotload(true) +require 'constants' +require 'config' require 'bar' +require 'default' require 'items' + +sbar.end_config() +sbar.event_loop() diff --git a/config/sketchybar/items/apple.lua b/config/sketchybar/items/apple.lua index 82cbde2..4b32680 100644 --- a/config/sketchybar/items/apple.lua +++ b/config/sketchybar/items/apple.lua @@ -1,37 +1,7 @@ -local colors = require 'colors' -local icons = require 'icons' -local settings = require 'settings' +local settings = require 'config.settings' --- Padding item required because of bracket -sbar.add('item', { width = 5 }) - -local apple = sbar.add('item', { - icon = { - font = { size = 16.0 }, - string = icons.apple, - padding_right = settings.paddings, - padding_left = 0, - color = colors.fg, - }, +local apple = sbar.add('item', 'apple', { + icon = { string = settings.icons.text.apple }, label = { drawing = false }, - background = { - color = colors.bar.bg, - -- border_color = colors.black, - -- border_width = 1 - }, - padding_left = 1, - padding_right = 1, click_script = 'sk-menus -s 0', }) - --- Double border for apple using a single item bracket --- sbar.add("bracket", { apple.name }, { --- background = { --- color = colors.transparent, --- height = 30, --- -- border_color = colors.grey, --- } --- }) - --- Padding item required because of bracket -sbar.add('item', { width = 7 }) diff --git a/config/sketchybar/items/front_apps.lua b/config/sketchybar/items/front_apps.lua new file mode 100644 index 0000000..7131786 --- /dev/null +++ b/config/sketchybar/items/front_apps.lua @@ -0,0 +1,61 @@ +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 = constants.aerospace_cmd .. ' 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/config/sketchybar/items/init.lua b/config/sketchybar/items/init.lua index 3c0fca2..0d2a868 100644 --- a/config/sketchybar/items/init.lua +++ b/config/sketchybar/items/init.lua @@ -1,34 +1,12 @@ -local function file_exists(path) - local f = io.open(path, 'r') - if f then - f:close() - return true - end - return false -end - -local function load_module_if_program_exists(module_name, binary_path) - if file_exists(binary_path) then - print('Loading ' .. module_name .. ' (found at ' .. binary_path .. ')') - local ok, err = pcall(require, module_name) - if not ok then - print('ERROR loading ' .. module_name .. ' module: ' .. tostring(err)) - else - print('Successfully loaded ' .. module_name) - end - else - print('Skipping ' .. module_name .. ' (binary not found at ' .. binary_path .. ')') - end -end - +-- Left items require 'items.apple' --- require 'items.aerospace' -load_module_if_program_exists('items.aerospace', '/opt/homebrew/bin/aerospace') -load_module_if_program_exists('items.yabai', '/etc/profiles/per-user/rayandrew/bin/yabai') -require 'items.front_app' -require 'items.menu' -require 'items.battery' -require 'items.cal' -require 'items.volume' -require 'items.cpu' -require 'items.wifi' +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/config/sketchybar/items/menu_spaces_toggle.lua b/config/sketchybar/items/menu_spaces_toggle.lua new file mode 100644 index 0000000..6702cfe --- /dev/null +++ b/config/sketchybar/items/menu_spaces_toggle.lua @@ -0,0 +1,75 @@ +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/config/sketchybar/items/menus.lua b/config/sketchybar/items/menus.lua new file mode 100644 index 0000000..5c40ee2 --- /dev/null +++ b/config/sketchybar/items/menus.lua @@ -0,0 +1,72 @@ +local constants = require 'constants' +local settings = require 'config.settings' + +local maxItems = 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 = 'sk-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('sk-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/config/sketchybar/items/message.lua b/config/sketchybar/items/message.lua new file mode 100644 index 0000000..4ff2963 --- /dev/null +++ b/config/sketchybar/items/message.lua @@ -0,0 +1,51 @@ +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/config/sketchybar/items/spaces.lua b/config/sketchybar/items/spaces.lua new file mode 100644 index 0000000..c7faa3b --- /dev/null +++ b/config/sketchybar/items/spaces.lua @@ -0,0 +1,179 @@ +local constants = require 'constants' +local settings = require 'config.settings' +local utils = require 'utils' + +local spaces = {} +local paddings = {} +local focusedWorkspace = nil + +local swapWatcher = sbar.add('item', { + drawing = false, + updates = true, +}) + +local currentWorkspaceWatcher = sbar.add('item', { + drawing = false, + updates = true, +}) + +-- Modify this file with Visual Studio Code - at least vim does have problems with the icons +-- copy "Icons" from the nerd fonts cheat sheet and replace icon and name accordingly below +-- https://www.nerdfonts.com/cheat-sheet +local spaceConfigs = { + ['1'] = { icon = '󱞁', name = 'Main' }, + ['2'] = { icon = '', name = '' }, + ['3'] = { icon = '', name = '' }, + ['4'] = { icon = '', name = '' }, + ['5'] = { icon = '', name = '' }, + ['6'] = { icon = '', name = '' }, + ['7'] = { icon = '󰎆', name = 'Music' }, + ['8'] = { icon = '󰇮', name = 'Mail' }, + ['9'] = { icon = '󰭹', name = 'Chat' }, + ['10'] = { icon = '󰖟', name = 'Browser' }, + ['t'] = { icon = '', name = 'Meeting' }, +} + +-- Track which workspaces have windows +local workspaceHasWindows = {} + +local updateWorkspaceVisibility = utils.coro.async(function() + local output = utils.coro.await(utils.coro.exec(constants.aerospace_cmd .. " list-windows --all --format '%{workspace}'")) + + -- Reset all + for ws, _ in pairs(workspaceHasWindows) do + workspaceHasWindows[ws] = false + end + + -- Mark workspaces that have windows + if output then + for ws in output:gmatch '[^\r\n]+' do + workspaceHasWindows[ws] = true + end + end + + -- Update visibility for each space + for workspaceName, _ in pairs(spaceConfigs) do + local spaceName = constants.items.SPACES .. '.' .. workspaceName + local space = spaces[spaceName] + local padding = paddings[spaceName] + + if space then + local hasWindows = workspaceHasWindows[workspaceName] == true + local isFocused = focusedWorkspace == workspaceName + local shouldShow = hasWindows or isFocused + + space:set { drawing = shouldShow } + if padding then padding:set { drawing = shouldShow } end + end + end +end) + +local function selectCurrentWorkspace(focusedWorkspaceName) + focusedWorkspace = focusedWorkspaceName + + for workspaceName, _ in pairs(spaceConfigs) do + local spaceName = constants.items.SPACES .. '.' .. workspaceName + local item = spaces[spaceName] + local padding = paddings[spaceName] + if item ~= nil then + local isSelected = workspaceName == focusedWorkspaceName + local hasWindows = workspaceHasWindows[workspaceName] == true + local shouldShow = hasWindows or isSelected + + -- Show/hide based on windows or focus + item:set { + drawing = shouldShow, + 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 }, + } + if padding then padding:set { drawing = shouldShow } end + end + end + + updateWorkspaceVisibility() + sbar.trigger(constants.events.UPDATE_WINDOWS) +end + +local findAndSelectCurrentWorkspace = utils.coro.async(function() + local focusedWorkspaceOutput = utils.coro.await(utils.coro.exec(constants.aerospace.GET_CURRENT_WORKSPACE)) + if focusedWorkspaceOutput then + local focusedWorkspaceName = focusedWorkspaceOutput:match '[^\r\n]+' + selectCurrentWorkspace(focusedWorkspaceName) + end +end) + +local function addWorkspaceItem(workspaceName) + local spaceName = constants.items.SPACES .. '.' .. workspaceName + local spaceConfig = spaceConfigs[workspaceName] + + -- Skip workspaces without a config entry + if not spaceConfig then return end + + local hasIcon = spaceConfig.icon and spaceConfig.icon ~= '' + local hasName = spaceConfig.name and spaceConfig.name ~= '' + local icon = hasIcon and spaceConfig.icon or workspaceName + local name = hasName and spaceConfig.name or workspaceName + local useBold = not hasIcon + local fontStyle = useBold and settings.fonts.styles.bold or settings.fonts.styles.regular + local iconFont = settings.fonts.text .. ':' .. fontStyle .. ':' .. settings.dimens.text.icon + + spaces[spaceName] = sbar.add('item', spaceName, { + drawing = false, -- start hidden, will show if has windows or is focused + label = { + width = 0, + padding_left = 0, + string = name, + }, + icon = { + string = icon, + font = iconFont, + color = settings.colors.white, + y_offset = useBold and 1 or 0, + }, + background = { + color = settings.colors.bg1, + }, + click_script = constants.aerospace_cmd .. ' 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) + + paddings[spaceName] = sbar.add('item', spaceName .. '.padding', { + drawing = false, + width = settings.dimens.padding.label, + }) +end + +local createWorkspaces = utils.coro.async(function() + local workspacesOutput = utils.coro.await(utils.coro.exec(constants.aerospace.LIST_ALL_WORKSPACES)) + if workspacesOutput then + for workspaceName in workspacesOutput:gmatch '[^\r\n]+' do + addWorkspaceItem(workspaceName) + end + end + + findAndSelectCurrentWorkspace() +end) + +swapWatcher:subscribe(constants.events.SWAP_MENU_AND_SPACES, function(env) + local isShowingSpaces = env.isShowingMenu == 'off' and true or false + if isShowingSpaces then + updateWorkspaceVisibility() + else + sbar.set('/' .. constants.items.SPACES .. '\\..*/', { drawing = false }) + end +end) + +currentWorkspaceWatcher:subscribe(constants.events.AEROSPACE_WORKSPACE_CHANGED, function(env) selectCurrentWorkspace(env.FOCUSED_WORKSPACE) end) + +-- Also update on window changes +currentWorkspaceWatcher:subscribe('front_app_switched', function(env) updateWorkspaceVisibility() end) + +createWorkspaces() diff --git a/config/sketchybar/items/widgets/battery.lua b/config/sketchybar/items/widgets/battery.lua new file mode 100644 index 0000000..5e8dcc4 --- /dev/null +++ b/config/sketchybar/items/widgets/battery.lua @@ -0,0 +1,89 @@ +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/config/sketchybar/items/widgets/calendar.lua b/config/sketchybar/items/widgets/calendar.lua new file mode 100644 index 0000000..48a128e --- /dev/null +++ b/config/sketchybar/items/widgets/calendar.lua @@ -0,0 +1,15 @@ +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/config/sketchybar/items/widgets/init.lua b/config/sketchybar/items/widgets/init.lua new file mode 100644 index 0000000..6caf06f --- /dev/null +++ b/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/config/sketchybar/items/widgets/volume.lua b/config/sketchybar/items/widgets/volume.lua new file mode 100644 index 0000000..ce24364 --- /dev/null +++ b/config/sketchybar/items/widgets/volume.lua @@ -0,0 +1,127 @@ +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/config/sketchybar/items/widgets/wifi.lua b/config/sketchybar/items/widgets/wifi.lua new file mode 100644 index 0000000..78f3f71 --- /dev/null +++ b/config/sketchybar/items/widgets/wifi.lua @@ -0,0 +1,247 @@ +local constants = require 'constants' +local settings = require 'config.settings' + +local popupWidth = settings.dimens.graphics.popup.width + 20 + +sbar.exec 'killall sk-network-load >/dev/null; sk-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) diff --git a/config/sketchybar/utils/coro.lua b/config/sketchybar/utils/coro.lua new file mode 100644 index 0000000..0dcedf7 --- /dev/null +++ b/config/sketchybar/utils/coro.lua @@ -0,0 +1,67 @@ +local M = {} + +-- Coroutine-based async/await helpers +function M.await(callback_fn) + local co = coroutine.running() + if not co then error 'await must be called inside async' end + + local result, err + local done = false + + callback_fn(function(res, e) + result = res + err = e + done = true + if coroutine.status(co) == 'suspended' then coroutine.resume(co) end + end) + + if not done then coroutine.yield() end + if err then error(err) end + return result +end + +function M.awaitAll(callback_fns) + local co = coroutine.running() + if not co then error 'awaitAll must be called inside async' end + + local results = {} + local pending = #callback_fns + local err = nil + + for i, fn in ipairs(callback_fns) do + fn(function(res, e) + if e then err = e end + results[i] = res + pending = pending - 1 + if pending == 0 and coroutine.status(co) == 'suspended' then coroutine.resume(co) end + end) + end + + if pending > 0 then coroutine.yield() end + if err then error(err) end + return results +end + +function M.async(fn) + return function(...) + local args = { ... } + local co = coroutine.create(function() fn(table.unpack(args)) end) + local ok, err = coroutine.resume(co) + if not ok then print('Async error: ' .. tostring(err)) end + end +end + +-- Execute a shell command, returns a callback function for use with await +function M.exec(cmd) + return function(resolve) + sbar.exec(cmd, function(result, exit_code) + if exit_code ~= 0 then + resolve(nil, string.format('Exit Code: %s Message: %s', tostring(exit_code), M.dump(result))) + else + resolve(result, nil) + end + end) + end +end + +return M diff --git a/config/sketchybar/utils/init.lua b/config/sketchybar/utils/init.lua new file mode 100644 index 0000000..3efb2f6 --- /dev/null +++ b/config/sketchybar/utils/init.lua @@ -0,0 +1,5 @@ +local coro = require 'utils.coro' + +return { + coro = coro, +} diff --git a/darwin/jankyborders.nix b/darwin/jankyborders.nix index 95c45c5..253d496 100644 --- a/darwin/jankyborders.nix +++ b/darwin/jankyborders.nix @@ -25,9 +25,11 @@ in enable = true; # active_color = "0xFFA1EFE4"; # inactive_color = "0xFFd3b58d"; - active_color = "0xFFFFFFFF"; - inactive_color = "0xFF000000"; - width = 5.0; + # active_color = "0xFFFFFFFF"; + # inactive_color = "0xFF000000"; + active_color = "0xFFFFBE69"; + inactive_color = "0xFF007692"; + width = 8.0; }; }; }