Compare commits

..

4 commits

Author SHA1 Message Date
0cf7e16710
make luarc json works 2025-11-29 18:30:09 -06:00
4c8ccec1ae
feat: new config for sketchybar 2025-11-29 17:39:02 -06:00
cc55237709
remove promise 2025-11-29 15:59:59 -06:00
572d3bfa80
feat: aerospace config 2025-11-29 15:34:43 -06:00
61 changed files with 2743 additions and 775 deletions

52
bin/presentation-mode Executable file
View file

@ -0,0 +1,52 @@
#!/bin/bash
# This script is used to change the top and bottom padding of the outer container in the Aerospace theme.
CONFIG_FILE="$HOME/.config/aerospace/aerospace.toml"
BACKUP_FILE="/tmp/aerospace_presentation_backup"
presentation_top_gaps=80
presentation_bottom_gaps=80
presentation_left_gaps=80
presentation_right_gaps=80
if [ "$1" == "on" ]; then
# Save original lines with line numbers
grep -n 'outer\.top\|outer\.bottom\|outer\.left\|outer\.right' "$CONFIG_FILE" > "$BACKUP_FILE"
# Replace with presentation values
sed -i'' -e "s/^\([[:space:]]*outer\.top[[:space:]]*=\).*/\1 ${presentation_top_gaps}/" "$CONFIG_FILE"
sed -i'' -e "s/^\([[:space:]]*outer\.bottom[[:space:]]*=\).*/\1 ${presentation_bottom_gaps}/" "$CONFIG_FILE"
sed -i'' -e "s/^\([[:space:]]*outer\.left[[:space:]]*=\).*/\1 ${presentation_left_gaps}/" "$CONFIG_FILE"
sed -i'' -e "s/^\([[:space:]]*outer\.right[[:space:]]*=\).*/\1 ${presentation_right_gaps}/" "$CONFIG_FILE"
# Set dark wallpaper for presentation
osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/black-gray.jpg"' > /dev/null 2>&1
aerospace reload-config
echo -n "Presentation mode ON"
elif [ "$1" == "off" ]; then
if [ ! -f "$BACKUP_FILE" ]; then
echo "Error: No backup found. Run 'presentation-mode on' first."
exit 1
fi
# Restore original values line by line
while IFS=: read -r line_num content; do
# Escape special characters for sed
escaped_content=$(printf '%s\n' "$content" | sed 's/[&/\]/\\&/g')
sed -i'' -e "${line_num}s/.*/${escaped_content}/" "$CONFIG_FILE"
done < "$BACKUP_FILE"
# Restore original wallpaper
osascript -e 'tell application "System Events" to set picture of every desktop to "/Users/rayandrew/Pictures/Wallpapers/bluering.png"' > /dev/null 2>&1
rm "$BACKUP_FILE"
aerospace reload-config
echo "Presentation mode OFF"
else
echo "Usage: presentation-mode [on|off]"
exit 1
fi

View file

@ -0,0 +1,155 @@
config-version = 2
after-startup-command = [
"workspace 10",
"workspace-back-and-forth"
]
persistent-workspaces = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
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_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$' = 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]
alt-enter = 'exec-and-forget open -na Ghostty'
alt-h = 'focus --boundaries-action wrap-around-the-workspace left'
alt-j = 'focus --boundaries-action wrap-around-the-workspace down'
alt-k = 'focus --boundaries-action wrap-around-the-workspace up'
alt-l = 'focus --boundaries-action wrap-around-the-workspace right'
alt-shift-h = 'move --boundaries all-monitors-outer-frame left'
alt-shift-j = 'move --boundaries all-monitors-outer-frame down'
alt-shift-k = 'move --boundaries all-monitors-outer-frame up'
alt-shift-l = 'move --boundaries all-monitors-outer-frame right'
alt-v = 'split vertical'
alt-shift-v = 'split horizontal'
alt-f = 'fullscreen'
alt-s = 'layout v_accordion'
alt-t = 'layout h_accordion'
alt-e = 'layout tiles horizontal vertical'
alt-space = 'layout floating tiling'
alt-1 = 'workspace 1'
alt-2 = 'workspace 2'
alt-3 = 'workspace 3'
alt-4 = 'workspace 4'
alt-5 = 'workspace 5'
alt-6 = 'workspace 6'
alt-7 = 'workspace 7'
alt-8 = 'workspace 8'
alt-9 = 'workspace 9'
alt-0 = 'workspace 10'
alt-shift-1 = 'move-node-to-workspace 1'
alt-shift-2 = 'move-node-to-workspace 2'
alt-shift-3 = 'move-node-to-workspace 3'
alt-shift-4 = 'move-node-to-workspace 4'
alt-shift-5 = 'move-node-to-workspace 5'
alt-shift-6 = 'move-node-to-workspace 6'
alt-shift-7 = 'move-node-to-workspace 7'
alt-shift-8 = 'move-node-to-workspace 8'
alt-shift-9 = 'move-node-to-workspace 9'
alt-shift-0 = 'move-node-to-workspace 10'
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"
[mode.resize.binding]
h = 'resize width -50'
j = 'resize height +50'
k = 'resize height -50'
l = 'resize width +50'
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]
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']
alt-shift-h = ['join-with left', 'mode main']
alt-shift-j = ['join-with down', 'mode main']
alt-shift-k = ['join-with up', 'mode main']
alt-shift-l = ['join-with right', 'mode main']
p = [
'exec-and-forget ~/dotfiles/bin/presentation-mode on',
'exec-and-forget /run/current-system/sw/bin/sketchybar --bar height=0',
'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger hide_message',
'mode main'
]
shift-p = [
'exec-and-forget ~/dotfiles/bin/presentation-mode off',
'exec-and-forget /run/current-system/sw/bin/sketchybar --bar height=30',
'exec-and-forget /run/current-system/sw/bin/sketchybar --trigger hide_message',
'mode main'
]
[[on-window-detected]]
if.app-id = 'com.apple.finder'
run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.apple.ActivityMonitor'
run = ['layout floating']
[[on-window-detected]]
if.app-id = 'com.1password.1password'
run = ['move-node-to-workspace 5']
[[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']

View file

@ -0,0 +1,10 @@
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime.version": "Lua 5.4",
"diagnostics.global": [
"hs"
],
"workspace.library": [
"/Applications/Hammerspoon.app/Contents/Resources"
]
}

View file

@ -1,12 +1,12 @@
local keymap = require 'keyboard.keymaps' local keymap = require 'keyboard.keymaps'
require 'keyboard.yabai' -- require 'keyboard.yabai'
-- General keymap -- General keymap
-- reload config -- reload config
keymap.super { -- keymap.super {
key = 'c', -- key = 'c',
mods = { 'shift' }, -- mods = { 'shift' },
message = 'Reload Hammerspoon config', -- message = 'Reload Hammerspoon config',
fn = function() hs.reload() end, -- fn = function() hs.reload() end,
} -- }

View file

@ -63,6 +63,17 @@ yabai_key { key = "'", commands = { 'space --layout stack' } }
yabai_key { key = ';', commands = { 'space --layout bsp' } } yabai_key { key = ';', commands = { 'space --layout bsp' } }
yabai_key { key = 'tab', commands = { 'space --focus recent' } } yabai_key { key = 'tab', commands = { 'space --focus recent' } }
-- toggle between bsp and stack layout
keymap.super {
key = 's',
message = 'Toggle layout (bsp/stack)',
fn = function()
local current_type = yabai_query('--spaces --space', "'.type'")
local new_layout = current_type == 'bsp' and 'stack' or 'bsp'
os.execute(yabai_cmd .. ' -m space --layout ' .. new_layout)
end,
}
-- navigation -- navigation
yabai_key { key = 'h', commands = { 'window --focus west', 'display --focus west' }, logic = 'or' } yabai_key { key = 'h', commands = { 'window --focus west', 'display --focus west' }, logic = 'or' }
yabai_key { key = 'j', commands = { 'window --focus south', 'display --focus south' }, logic = 'or' } yabai_key { key = 'j', commands = { 'window --focus south', 'display --focus south' }, logic = 'or' }

17
config/nvim/.luarc.json Normal file
View file

@ -0,0 +1,17 @@
{
"runtime": {
"version": "LuaJIT"
},
"diagnostics": {
"globals": ["vim"]
},
"workspace": {
"checkThirdParty": false
},
"completion": {
"callSnippet": "Replace"
},
"telemetry": {
"enable": false
}
}

View file

@ -420,37 +420,10 @@ later(function()
} }
-- Setup language servers using vim.lsp.config -- Setup language servers using vim.lsp.config
-- Lua -- Lua (settings in .luarc.json, library paths handled by lazydev)
local runtime_path = vim.split(package.path, ';')
table.insert(runtime_path, 'lua/?.lua')
table.insert(runtime_path, 'lua/?/init.lua')
vim.lsp.config.lua_ls = { vim.lsp.config.lua_ls = {
cmd = { 'lua-language-server' }, cmd = { 'lua-language-server' },
root_markers = { '.luarc.json', '.luarc.jsonc', '.luacheckrc', '.stylua.toml', 'stylua.toml', 'selene.toml', 'selene.yml', '.git' }, root_markers = { '.luarc.json', '.luarc.jsonc', '.luacheckrc', '.stylua.toml', 'stylua.toml', 'selene.toml', 'selene.yml', '.git' },
settings = {
Lua = {
runtime = {
version = 'LuaJIT',
path = runtime_path,
},
diagnostics = {
globals = { 'vim' },
},
workspace = {
library = {
vim.env.VIMRUNTIME,
'${3rd}/luv/library',
vim.fn.stdpath 'data' .. '/site/pack/deps/start',
},
checkThirdParty = false,
},
completion = {
callSnippet = 'Replace',
},
telemetry = { enable = false },
},
},
} }
-- TypeScript/JavaScript -- TypeScript/JavaScript

View file

@ -0,0 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime.version": "Lua 5.4",
"diagnostics.global": [
"sbar"
]
}

View file

@ -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,
}

View file

@ -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'

View file

@ -0,0 +1,246 @@
local colors = require 'colors'
local utils = require 'utils'
local settings = require 'settings'
local app_icons = require 'app_icons'
local async = utils.async
local await = utils.await
local awaitAll = utils.awaitAll
local exec = utils.exec
local aerospace_cmd = '/opt/homebrew/bin/aerospace'
-- Aerospace commands
local function getAllWorkspaces()
return exec(aerospace_cmd .. " list-workspaces --all --format '%{workspace}%{monitor-appkit-nsscreen-screens-id}%{monitor-id}%{monitor-name}' --json")
end
local function getVisibleWorkspaces()
return exec(
aerospace_cmd .. " list-workspaces --visible --monitor all --format '%{workspace}%{monitor-appkit-nsscreen-screens-id}%{monitor-id}%{monitor-name}' --json"
)
end
local function getAllWindows()
return exec(
aerospace_cmd
.. " list-windows --all --format '%{app-name}%{window-title}%{workspace}%{monitor-id}%{monitor-appkit-nsscreen-screens-id}%{monitor-name}' --json"
)
end
local function getMonitorId(obj)
if obj['monitor-name'] then
if obj['monitor-name'] == 'ZOWIE XL LCD' then
return 2
elseif obj['monitor-name'] == 'LG ULTRAWIDE' then
return 1
end
end
if obj['monitor-appkit-nsscreen-screens-id'] then return tonumber(obj['monitor-appkit-nsscreen-screens-id']) or 1 end
return tonumber(obj['monitor-id']) or 1
end
-- State
local spaces = {}
local space_paddings = {}
local state = {
workspaces = {},
updating = false,
}
-- Build app icons string from app list
local function buildAppIcons(apps)
local appkeys = {}
for app in pairs(apps) do
table.insert(appkeys, app)
end
table.sort(appkeys)
if #appkeys == 0 then return '' end
local icons = ''
for _, app in ipairs(appkeys) do
local lookup = app_icons[app]
local icon = lookup or app_icons['Default']
icons = icons .. ' ' .. icon
end
return icons
end
-- Fetch and build workspace state
local fetchState = async(function()
if state.updating then return end
state.updating = true
local ok, err = pcall(function()
local all, visible, windows = table.unpack(awaitAll {
getAllWorkspaces(),
getVisibleWorkspaces(),
getAllWindows(),
})
local newstate = { workspaces = {} }
-- Initialize all workspaces
for workspaceid, _ in pairs(spaces) do
newstate.workspaces[workspaceid] = {
id = workspaceid,
monitor = 1,
active = false,
empty = true,
apps = {},
}
end
-- Set monitor IDs
for _, ws in ipairs(all) do
local id = ws['workspace']
if newstate.workspaces[id] then newstate.workspaces[id].monitor = getMonitorId(ws) end
end
-- Mark visible workspaces as active
for _, ws in ipairs(visible) do
local id = ws['workspace']
if newstate.workspaces[id] then newstate.workspaces[id].active = true end
end
-- Collect apps per workspace
for _, win in ipairs(windows) do
local id = win['workspace']
local app = win['app-name']
if newstate.workspaces[id] then
newstate.workspaces[id].apps[app] = true
newstate.workspaces[id].empty = false
end
end
-- Build app icons
for _, ws in pairs(newstate.workspaces) do
ws.appicons = buildAppIcons(ws.apps)
end
state.workspaces = newstate.workspaces
end)
state.updating = false
if not ok then print('Error fetching state: ' .. tostring(err)) end
end)
-- Sync UI with state
local function syncState()
sbar.animate('tanh', 10, function()
for id, ws in pairs(state.workspaces) do
local shouldShow = not ws.empty or ws.active
spaces[id]:set {
drawing = shouldShow,
display = ws.monitor,
label = {
string = ws.appicons,
highlight = ws.active,
},
icon = {
highlight = ws.active,
},
}
space_paddings[id]:set { drawing = shouldShow }
end
end)
end
local function updateStateAndSync()
fetchState()
-- Use a small delay to let fetchState complete before syncing
sbar.exec('sleep 0.1', syncState)
end
-- Handle workspace change event
local function onActiveSpaceChange(env)
local focused = env.FOCUSED_WORKSPACE
local prev = env.PREV_WORKSPACE
-- Immediately update UI for responsiveness
if spaces[focused] then
sbar.animate('tanh', 10, function()
spaces[focused]:set {
drawing = true,
icon = { highlight = true },
label = { highlight = true },
}
space_paddings[focused]:set { drawing = true }
if spaces[prev] then
spaces[prev]:set {
icon = { highlight = false },
label = { highlight = false },
}
if state.workspaces[prev] and state.workspaces[prev].empty then
spaces[prev]:set { drawing = false }
space_paddings[prev]:set { drawing = false }
end
end
end)
end
updateStateAndSync()
end
-- Setup
local setup = async(function()
local workspaces = await(getAllWorkspaces())
-- Create space items
for _, ws in ipairs(workspaces) do
local id = ws['workspace']
local display = getMonitorId(ws)
local space = sbar.add('item', 'space.' .. id, {
drawing = false,
updates = 'when_shown',
display = display,
icon = {
string = id,
color = colors.fg,
highlight_color = colors.red,
},
label = {
padding_right = 12,
color = colors.fg,
highlight_color = colors.blue,
font = 'sketchybar-app-font:Regular:14.0',
y_offset = -1,
},
padding_left = 1,
padding_right = 1,
click_script = aerospace_cmd .. ' workspace ' .. id,
})
spaces[id] = space
local padding = sbar.add('space', 'space.padding.' .. space.name, {
drawing = false,
updates = 'when_shown',
display = display,
script = '',
width = settings.space_paddings,
})
space_paddings[id] = padding
end
-- Register events
sbar.add('event', 'aerospace_workspace_change')
local observer = sbar.add('item', {
drawing = false,
updates = true,
})
observer:subscribe('aerospace_workspace_change', onActiveSpaceChange)
observer:subscribe('space_windows_change', updateStateAndSync)
observer:subscribe('system_woke', updateStateAndSync)
observer:subscribe('front_app_switched', updateStateAndSync)
-- Initial state sync
updateStateAndSync()
end)
setup()

View file

@ -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 })

View file

@ -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'

View file

@ -0,0 +1,80 @@
local M = {}
function M.dump(o)
if type(o) == 'table' then
local s = '{'
for k, v in pairs(o) do
if type(k) ~= 'number' then k = '"' .. k .. '"' end
s = s .. ' [' .. k .. '] = ' .. M.dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end
-- 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

View file

@ -0,0 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime.version": "Lua 5.4",
"diagnostics.global": [
"sbar"
]
}

View file

@ -0,0 +1 @@
Shamelessly copied from https://github.com/agenttank/dotfiles_macos/tree/1feca82518312cd8c4a784032471fedfa895989d

View file

@ -1,23 +1,15 @@
#!/usr/bin/env lua local settings = require 'config.settings'
local colors = require 'colors'
local bar_height = 35
sbar.bar { sbar.bar {
blur_radius = 20, topmost = 'window',
border_color = colors.bar.border, height = settings.dimens.graphics.bar.height,
border_width = 2, color = settings.colors.bar.transparent,
color = colors.bar.bg, padding_right = settings.dimens.padding.right,
corner_radius = 5, padding = settings.dimens.padding.bar,
height = bar_height, padding_left = settings.dimens.padding.left,
margin = 10, margin = settings.dimens.padding.bar,
notch_width = 0, corner_radius = settings.dimens.graphics.background.corner_radius,
padding_left = 10, y_offset = settings.dimens.graphics.bar.offset,
padding_right = 10, -- blur_radius = settings.dimens.graphics.blur_radius,
position = 'top', border_width = 0,
shadow = true,
sticky = true,
topmost = false,
y_offset = 2,
} }

View file

@ -0,0 +1,38 @@
local colors <const> = {
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

View file

@ -0,0 +1,40 @@
local padding <const> = {
background = 8,
icon = 10,
label = 8,
bar = 10,
left = 12,
right = 12,
item = 18,
popup = 8,
}
local graphics <const> = {
bar = {
height = 30,
offset = 5,
},
background = {
height = 24,
corner_radius = 9,
},
slider = {
height = 20,
},
popup = {
width = 200,
large_width = 300,
},
blur_radius = 30,
}
local text <const> = {
icon = 16.0,
label = 14.0,
}
return {
padding = padding,
graphics = graphics,
text = text,
}

View file

@ -0,0 +1,14 @@
local dimens <const> = 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',
},
}

View file

@ -0,0 +1,331 @@
local apps <const> = {
['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 <const> = {
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,
}

View file

@ -0,0 +1 @@
return require 'config.settings'

View file

@ -0,0 +1,11 @@
local colors <const> = require 'config.colors'
local fonts <const> = require 'config.fonts'
local icons <const> = require 'config.icons'
local dimens <const> = require 'config.dimens'
return {
fonts = fonts,
dimens = dimens,
colors = colors,
icons = icons,
}

View file

@ -0,0 +1,37 @@
local events <const> = {
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 <const> = {
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 <const> = '/opt/homebrew/bin/aerospace'
local aerospace <const> = {
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,
}

View file

@ -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,
}

View file

@ -1,56 +1,13 @@
#!/usr/bin/env lua sbar = require 'sketchybar'
local colors = require 'colors' sbar.begin_config()
local settings = require 'settings' sbar.hotload(true)
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 'constants'
require 'config'
require 'bar' require 'bar'
require 'default'
require 'items' require 'items'
sbar.end_config()
sbar.event_loop()

View file

@ -1,242 +0,0 @@
-- https://github.com/Tnixc/nix-config/blob/main/home/programs/aerospace-sketchybar/sbar-config-libs/items/aerospaces.lua
local Promise = require 'promise'
local colors = require 'colors'
local utils = require 'utils'
local settings = require 'settings'
local app_icons = require 'app_icons'
local function getAllWorkspaces()
return utils.sbarExecP "aerospace list-workspaces --all --format '%{workspace}%{monitor-appkit-nsscreen-screens-id}%{monitor-id}%{monitor-name}' --json"
end
local function getVisibleWorkspaces()
return utils.sbarExecP "aerospace list-workspaces --visible --monitor all --format '%{workspace}%{monitor-appkit-nsscreen-screens-id}%{monitor-id}%{monitor-name}' --json"
end
local function getAllWindows()
return utils.sbarExecP "aerospace list-windows --all --format '%{app-name}%{window-title}%{workspace}%{monitor-id}%{monitor-appkit-nsscreen-screens-id}%{monitor-name}' --json"
end
local function getMonitorId(obj)
if obj['monitor-name'] then
if obj['monitor-name'] == 'ZOWIE XL LCD' then
return '2'
elseif obj['monitor-name'] == 'LG ULTRAWIDE' then
return '1'
end
end
if obj['monitor-appkit-nsscreen-screens-id'] then return obj['monitor-appkit-nsscreen-screens-id'] end
return obj['monitor-id']
end
local spaces = {}
local space_paddings = {}
local brackets = {}
local state = {
workspaces = {},
updating = false,
}
function getState()
local newstate = {
workspaces = {},
}
for workspaceid, space in pairs(spaces) do
newstate.workspaces[workspaceid] = {
monitor = 0,
active = false,
empty = true,
apps = {},
appicons = '',
}
end
return Promise.all({ getAllWorkspaces(), getVisibleWorkspaces(), getAllWindows() }):thenCall(function(values)
local all, visible, apps = values[1], values[2], values[3]
for _, workspace in ipairs(all) do
local workspaceid = workspace['workspace']
newstate.workspaces[workspaceid]['id'] = workspaceid
newstate.workspaces[workspaceid]['monitor'] = getMonitorId(workspace)
end
for _, workspace in ipairs(visible) do
local workspaceid = workspace['workspace']
newstate.workspaces[workspaceid]['active'] = true
end
for _, window in ipairs(apps) do
local workspaceid = window['workspace']
local appname = window['app-name']
newstate.workspaces[workspaceid]['apps'][appname] = true
newstate.workspaces[workspaceid]['empty'] = false
end
for workspaceid, workspacestate in pairs(newstate.workspaces) do
local appkeys = {}
for app in pairs(workspacestate['apps']) do
table.insert(appkeys, app)
end
table.sort(appkeys)
if #appkeys > 0 then
for _, app in ipairs(appkeys) do
local lookup = app_icons[app]
local icon = ((lookup == nil) and app_icons['Default'] or lookup)
workspacestate['appicons'] = workspacestate['appicons'] .. ' ' .. icon
end
else
workspacestate['appicons'] = ''
end
-- print(utils.dump(workspacestate))
end
return newstate
end)
end
local function updateState()
if not state.updating then
state.updating = true
return getState():thenCall(function(newstate)
state.workspaces = newstate.workspaces
state.updating = false
end)
end
return Promise.reject 'State is already updating'
end
local function highlightSpace(space, space_padding, space_bracket, selected)
space:set {
drawing = true,
icon = { highlight = selected },
label = { highlight = selected },
-- background = { border_color = selected and colors.white or colors.bg2 }
}
space_padding:set {
drawing = true,
}
if space_bracket then
space_bracket:set {
-- background = { border_color = selected and colors.grey or colors.bg2 },
}
end
end
local function onActiveSpaceChange(env)
local focused_workspace = env.FOCUSED_WORKSPACE
local last_workspace = env.PREV_WORKSPACE
-- print("aerospace_workspace_change from " .. last_workspace .. " to " .. focused_workspace)
local space = spaces[focused_workspace]
local space_padding = space_paddings[focused_workspace]
local prev_space = spaces[last_workspace]
local prev_space_padding = space_paddings[last_workspace]
sbar.animate('tanh', 10, function()
highlightSpace(space, space_padding, nil, true)
if state.workspaces[last_workspace]['monitor'] == state.workspaces[focused_workspace]['monitor'] then
highlightSpace(prev_space, prev_space_padding, nil, false)
end
end)
updateState()
end
local function syncState()
sbar.animate('tanh', 10, function()
for workspaceid, workspacestate in pairs(state.workspaces) do
if not workspacestate['empty'] then
spaces[workspaceid]:set {
drawing = true,
display = workspacestate['monitor'],
-- label = {
-- string = workspaceid,
-- highlight = workspacestate["active"],
-- },
-- icon = {
-- string = workspaceid,
-- color = colors.white,
-- highlight = workspacestate["active"],
-- },
label = {
string = workspacestate['appicons'],
highlight = workspacestate['active'],
},
icon = {
highlight = workspacestate['active'],
},
}
space_paddings[workspaceid]:set { drawing = true }
else
-- These should be hidden
spaces[workspaceid]:set {
drawing = false,
display = workspacestate['monitor'],
label = workspacestate['appicons'],
}
space_paddings[workspaceid]:set { drawing = false }
end
end
end)
end
local function updateStateAndSync() return updateState():thenCall(syncState) end
function setup()
getAllWorkspaces()
:thenCall(function(workspaces)
for _, workspace in ipairs(workspaces) do
local workspaceid = workspace['workspace']
local display = getMonitorId(workspace)
local space = sbar.add('item', 'space.' .. workspaceid, {
drawing = false, -- default to not showing the space -- we'll show if it has windows or is activated
updates = 'when_shown',
display = display,
icon = {
string = workspaceid,
color = colors.fg,
highlight_color = colors.red,
},
label = {
padding_right = 12,
color = colors.fg,
highlight_color = colors.blue,
font = 'sketchybar-app-font:Regular:14.0',
y_offset = -1,
-- drawing = false
},
padding_left = 1,
padding_right = 1,
click_script = 'aerospace workspace ' .. workspaceid,
})
spaces[workspaceid] = space
local padding = sbar.add('space', 'space.padding.' .. space.name, {
drawing = false,
updates = 'when_shown',
display = display,
script = '',
width = settings.space_paddings,
})
space_paddings[workspaceid] = padding
end
end)
:thenCall(function()
local space_window_observer = sbar.add('item', {
drawing = false,
updates = true,
})
space_window_observer:subscribe('aerospace_workspace_change', onActiveSpaceChange)
space_window_observer:subscribe('space_windows_change', updateStateAndSync)
space_window_observer:subscribe('system_woke', updateStateAndSync)
space_window_observer:subscribe('front_app_switched', updateStateAndSync)
end)
:thenCall(updateStateAndSync)
end
setup()

View file

@ -1,37 +1,7 @@
local colors = require 'colors' local settings = require 'config.settings'
local icons = require 'icons'
local settings = require 'settings'
-- Padding item required because of bracket local apple = sbar.add('item', 'apple', {
sbar.add('item', { width = 5 }) icon = { string = settings.icons.text.apple },
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 }, 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', 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 })

View file

@ -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()

View file

@ -1,33 +1,12 @@
local function file_exists(path) -- Left items
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.apple'
load_module_if_program_exists('items.aerospace', '/opt/homebrew/bin/aerospace') require 'items.menu_spaces_toggle'
load_module_if_program_exists('items.yabai', '/etc/profiles/per-user/rayandrew/bin/yabai') require 'items.menus'
require 'items.front_app' require 'items.spaces'
require 'items.menu' require 'items.front_apps'
require 'items.battery'
require 'items.cal' -- Right items
require 'items.volume' require 'items.message'
require 'items.cpu' require 'items.widgets'
require 'items.wifi'
-- require("items.media")

View file

@ -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()

View file

@ -0,0 +1,72 @@
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 = '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()

View file

@ -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)

View file

@ -0,0 +1,180 @@
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 <const> = {
['1'] = { icon = '󱞁', name = 'Main' },
['2'] = { icon = '', name = '' },
['3'] = { icon = '', name = '' },
['4'] = { icon = '', name = '' },
['5'] = { icon = '󰌾', name = 'Misc' },
['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,
y_offset = 1,
},
icon = {
string = icon,
font = iconFont,
color = settings.colors.white,
y_offset = 1,
},
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()

View file

@ -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)

View file

@ -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)

View file

@ -0,0 +1,4 @@
require 'items.widgets.calendar'
require 'items.widgets.battery'
require 'items.widgets.volume'
require 'items.widgets.wifi'

View file

@ -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)

View file

@ -0,0 +1,247 @@
local constants = require 'constants'
local settings = require 'config.settings'
local popupWidth <const> = 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)

View file

@ -1,33 +0,0 @@
local Promise = require 'promise'
local M = {}
function M.dump(o)
if type(o) == 'table' then
local s = '{'
for k, v in pairs(o) do
if type(k) ~= 'number' then k = '"' .. k .. '"' end
s = s .. ' [' .. k .. '] = ' .. M.dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end
local function onErrorP(reason) print('Error found: ' .. (reason and M.dump(reason) or 'unknown')) end
-- https://github.com/Tnixc/nix-config/blob/main/home/programs/aerospace-sketchybar/sbar-config-libs/items/aerospaces.lua
function M.sbarExecP(cmd)
return Promise.new(function(resolve, failfunc)
sbar.exec(cmd, function(result, exit_code)
if exit_code ~= 0 then
if failfunc ~= nil then failfunc(string.format('Exit Code: %s Message: %s', tostring(exit_code), M.dump(result))) end
else
if resolve ~= nil then resolve(result) end
end
end)
end):catch(onErrorP)
end
return M

View file

@ -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

View file

@ -0,0 +1,5 @@
local coro <const> = require 'utils.coro'
return {
coro = coro,
}

View file

@ -1,8 +1,9 @@
{ {
pkgs,
lib, lib,
config, config,
home-dir, dots,
pkgs,
inputs,
... ...
}: }:
@ -13,305 +14,310 @@ in
options.custom.gui = with lib; { options.custom.gui = with lib; {
aerospace = { aerospace = {
enable = mkEnableOption "Enable aerospace"; enable = mkEnableOption "Enable aerospace";
logFile = mkOption { # logFile = mkOption {
type = types.str; # type = types.str;
default = "${home-dir}/Library/Logs/aerospace.log"; # default = "${home-dir}/Library/Logs/aerospace.log";
description = "Filepath of log output"; # description = "Filepath of log output";
}; # };
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
launchd.user.agents.aerospace.serviceConfig = { hm.home.packages = [
StandardErrorPath = cfg.logFile; inputs.aerospace-scratchpad.packages.${pkgs.stdenv.hostPlatform.system}.default
StandardOutPath = cfg.logFile;
};
services.aerospace = {
enable = true;
# package = pkgs.custom.aerospace;
settings = {
enable-normalization-flatten-containers = false;
enable-normalization-opposite-orientation-for-nested-containers = false;
accordion-padding = 0;
on-focused-monitor-changed = [ "move-mouse monitor-lazy-center" ];
default-root-container-layout = "tiles";
default-root-container-orientation = "auto";
after-startup-command = [
"workspace 10"
"layout h_accordion"
"workspace-back-and-forth"
]; ];
hm.xdg.configFile."aerospace".source =
gaps = { config.hm.lib.file.mkOutOfStoreSymlink "${dots}/config/aerospace";
inner = { # launchd.user.agents.aerospace.serviceConfig = {
horizontal = 15; # StandardErrorPath = cfg.logFile;
vertical = 15; # StandardOutPath = cfg.logFile;
}; # };
outer = { #
left = 10; # services.aerospace = {
bottom = 5; # enable = true;
top = [ # # package = pkgs.custom.aerospace;
{ monitor."LG ULTRAWIDE" = 50; } # settings = {
{ monitor."ZOWIE XL LCD" = 50; } # enable-normalization-flatten-containers = false;
12 # enable-normalization-opposite-orientation-for-nested-containers = false;
]; # accordion-padding = 0;
right = 10; # on-focused-monitor-changed = [ "move-mouse monitor-lazy-center" ];
}; # default-root-container-layout = "tiles";
}; # default-root-container-orientation = "auto";
# after-startup-command = [
mode = {
main = {
binding = {
alt-enter =
let
script = pkgs.writeText "ghostty.applescript" ''
do shell script "open -n -a Ghostty"
'';
in
"exec-and-forget osascript ${script}";
# alt-enter = "exec-and-forget \"open -n -a /Applications/Slack.app\"";
alt-shift-f = "fullscreen";
alt-shift-q = "close --quit-if-last-window";
alt-space = "layout floating tiling";
alt-e = "layout tiles horizontal vertical";
alt-t = "layout h_accordion";
alt-s = "layout v_accordion";
alt-v = "split vertical";
alt-shift-v = "split horizontal";
# alt-v = "join-with down";
# alt-shift-v = "join-with right";
alt-h = "focus --boundaries-action wrap-around-the-workspace left";
alt-l = "focus --boundaries-action wrap-around-the-workspace right";
alt-j = "focus --boundaries-action wrap-around-the-workspace down";
alt-k = "focus --boundaries-action wrap-around-the-workspace up";
alt-shift-h = "move left";
alt-shift-l = "move right";
alt-shift-j = "move down";
alt-shift-k = "move up";
cmd-h = [ ]; # Disable "hide application"
cmd-alt-h = [ ]; # Disable "hide others"
cmd-q = [ ]; # Disable "quit"
cmd-shift-q = [ ]; # Disable "logout"
alt-1 = "workspace 1";
alt-2 = "workspace 2";
alt-3 = "workspace 3";
alt-4 = "workspace 4";
alt-5 = "workspace 5";
alt-6 = "workspace 6";
alt-7 = "workspace 7";
alt-8 = "workspace 8";
alt-9 = "workspace 9";
alt-0 = "workspace 10";
alt-shift-1 = [
"move-node-to-workspace 1"
# "workspace 1"
];
alt-shift-2 = [
"move-node-to-workspace 2"
# "workspace 2"
];
alt-shift-3 = [
"move-node-to-workspace 3"
# "workspace 3"
];
alt-shift-4 = [
"move-node-to-workspace 4"
# "workspace 4"
];
alt-shift-5 = [
"move-node-to-workspace 5"
# "workspace 5"
];
alt-shift-6 = [
"move-node-to-workspace 6"
# "workspace 6"
];
alt-shift-7 = [
"move-node-to-workspace 7"
# "workspace 7"
];
alt-shift-8 = [
"move-node-to-workspace 8"
# "workspace 8"
];
alt-shift-9 = [
"move-node-to-workspace 9"
# "workspace 9"
];
alt-shift-0 = [
"move-node-to-workspace 10"
# "workspace 10" # "workspace 10"
]; # "layout h_accordion"
# "workspace-back-and-forth"
alt-shift-c = "reload-config"; # ];
alt-tab = "workspace-back-and-forth"; #
alt-shift-tab = "move-workspace-to-monitor --wrap-around next"; # gaps = {
alt-r = "mode resize"; # inner = {
alt-shift-semicolon = "mode service"; # horizontal = 15;
}; # vertical = 15;
}; # };
# outer = {
service = { # left = 10;
binding = { # bottom = 5;
esc = [ # top = [
"reload-config" # { monitor."LG ULTRAWIDE" = 50; }
"mode main" # { monitor."ZOWIE XL LCD" = 50; }
]; # 12
r = [ # ];
"flatten-workspace-tree" # right = 10;
"mode main" # };
]; # };
f = [ #
"layout floating tiling" # mode = {
"mode main" # main = {
]; # binding = {
backspace = [ # alt-enter =
"close-all-windows-but-current" # let
"mode main" # script = pkgs.writeText "ghostty.applescript" ''
]; # do shell script "open -n -a Ghostty"
# '';
alt-shift-h = [ # in
"join-with left" # "exec-and-forget osascript ${script}";
"mode main" #
]; # # alt-enter = "exec-and-forget \"open -n -a /Applications/Slack.app\"";
alt-shift-j = [ #
"join-with down" # alt-shift-f = "fullscreen";
"mode main" # alt-shift-q = "close --quit-if-last-window";
]; # alt-space = "layout floating tiling";
alt-shift-k = [ # alt-e = "layout tiles horizontal vertical";
"join-with up" # alt-t = "layout h_accordion";
"mode main" # alt-s = "layout v_accordion";
]; # alt-v = "split vertical";
alt-shift-l = [ # alt-shift-v = "split horizontal";
"join-with right" # # alt-v = "join-with down";
"mode main" # # alt-shift-v = "join-with right";
]; # alt-h = "focus --boundaries-action wrap-around-the-workspace left";
# alt-l = "focus --boundaries-action wrap-around-the-workspace right";
# down = "volume down"; # alt-j = "focus --boundaries-action wrap-around-the-workspace down";
# up = "volume up"; # alt-k = "focus --boundaries-action wrap-around-the-workspace up";
# shift-down = [ "volume set 0" "mode main" ]; # alt-shift-h = "move left";
}; # alt-shift-l = "move right";
}; # alt-shift-j = "move down";
# alt-shift-k = "move up";
resize = { #
binding = { # cmd-h = [ ]; # Disable "hide application"
h = "resize width -50"; # cmd-alt-h = [ ]; # Disable "hide others"
j = "resize height +50"; # cmd-q = [ ]; # Disable "quit"
k = "resize height -50"; # cmd-shift-q = [ ]; # Disable "logout"
l = "resize width +50"; #
enter = "mode main"; # alt-1 = "workspace 1";
esc = "mode main"; # alt-2 = "workspace 2";
}; # alt-3 = "workspace 3";
}; # alt-4 = "workspace 4";
}; # alt-5 = "workspace 5";
# alt-6 = "workspace 6";
workspace-to-monitor-force-assignment = { # alt-7 = "workspace 7";
"1" = "main"; # alt-8 = "workspace 8";
"2" = "main"; # alt-9 = "workspace 9";
"3" = "main"; # alt-0 = "workspace 10";
"4" = "main"; #
"5" = "main"; # alt-shift-1 = [
"6" = "main"; # "move-node-to-workspace 1"
"7" = [ # # "workspace 1"
"2" # ];
"main" # alt-shift-2 = [
]; # "move-node-to-workspace 2"
"8" = "main"; # # "workspace 2"
"9" = "main"; # ];
"10" = [ # alt-shift-3 = [
"2" # "move-node-to-workspace 3"
"main" # # "workspace 3"
]; # ];
}; # alt-shift-4 = [
# "move-node-to-workspace 4"
on-window-detected = [ # # "workspace 4"
# workspace # ];
# media # alt-shift-5 = [
{ # "move-node-to-workspace 5"
"if".app-id = "com.spotify.client"; # # "workspace 5"
run = [ "move-node-to-workspace 7" ]; # ];
} # alt-shift-6 = [
# browser # "move-node-to-workspace 6"
{ # # "workspace 6"
"if".app-id = "app.zen-browser.zen"; # ];
run = [ "move-node-to-workspace 10" ]; # alt-shift-7 = [
} # "move-node-to-workspace 7"
{ # # "workspace 7"
"if".app-id = "com.kagi.kagimacOS"; # ];
run = [ # alt-shift-8 = [
"move-node-to-workspace 10" # "move-node-to-workspace 8"
]; # # "workspace 8"
} # ];
# alt-shift-9 = [
# "move-node-to-workspace 9"
# # "workspace 9"
# ];
# alt-shift-0 = [
# "move-node-to-workspace 10"
# # "workspace 10"
# ];
#
# alt-shift-c = "reload-config";
# alt-tab = "workspace-back-and-forth";
# alt-shift-tab = "move-workspace-to-monitor --wrap-around next";
# alt-r = "mode resize";
# alt-shift-semicolon = "mode service";
# };
# };
#
# service = {
# binding = {
# esc = [
# "reload-config"
# "mode main"
# ];
# r = [
# "flatten-workspace-tree"
# "mode main"
# ];
# f = [
# "layout floating tiling"
# "mode main"
# ];
# backspace = [
# "close-all-windows-but-current"
# "mode main"
# ];
#
# alt-shift-h = [
# "join-with left"
# "mode main"
# ];
# alt-shift-j = [
# "join-with down"
# "mode main"
# ];
# alt-shift-k = [
# "join-with up"
# "mode main"
# ];
# alt-shift-l = [
# "join-with right"
# "mode main"
# ];
#
# # down = "volume down";
# # up = "volume up";
# # shift-down = [ "volume set 0" "mode main" ];
# };
# };
#
# resize = {
# binding = {
# h = "resize width -50";
# j = "resize height +50";
# k = "resize height -50";
# l = "resize width +50";
# enter = "mode main";
# esc = "mode main";
# };
# };
# };
#
# workspace-to-monitor-force-assignment = {
# "1" = "main";
# "2" = "main";
# "3" = "main";
# "4" = "main";
# "5" = "main";
# "6" = "main";
# "7" = [
# "2"
# "main"
# ];
# "8" = "main";
# "9" = "main";
# "10" = [
# "2"
# "main"
# ];
# };
#
# on-window-detected = [
# # workspace
# # media
# { # {
# "if".app-id = "com.openai.chat"; # "if".app-id = "com.spotify.client";
# run = [ "move-node-to-workspace 7" ];
# }
# # browser
# {
# "if".app-id = "app.zen-browser.zen";
# run = [ "move-node-to-workspace 10" ];
# }
# {
# "if".app-id = "com.kagi.kagimacOS";
# run = [ # run = [
# "move-node-to-workspace 10" # "move-node-to-workspace 10"
# ]; # ];
# } # }
# # {
# # "if".app-id = "com.openai.chat";
# # run = [
# # "move-node-to-workspace 10"
# # ];
# # }
# # {
# # "if".app-id = "app.mozilla.firefox";
# # run = [ "move-node-to-workspace 10" ];
# # }
# # {
# # "if".app-id = "com.google.Chrome";
# # run = [ "move-node-to-workspace 10" ];
# # }
# # {
# # "if".app-id = "org.chromium.Chromium";
# # run = [ "move-node-to-workspace 10" ];
# # }
# # communications
# { # {
# "if".app-id = "app.mozilla.firefox"; # "if".app-id = "com.tinyspeck.slackmacgap";
# run = [ "move-node-to-workspace 10" ]; # run = [ "move-node-to-workspace 9" ];
# } # }
# { # {
# "if".app-id = "com.google.Chrome"; # "if".app-id = "com.microsoft.teams2";
# run = [ "move-node-to-workspace 10" ]; # run = [ "move-node-to-workspace 9" ];
# }
# # special app's layout
# ## tiling
# {
# "if".app-id = "com.mitchellh.ghostty";
# run = [ "layout tiling" ];
# }
# ## floating
# {
# "if".app-id = "com.renfei.SnippetsLab";
# run = [ "layout floating" ];
# } # }
# { # {
# "if".app-id = "org.chromium.Chromium"; # "if".app-id = "com.colliderli.iina";
# run = [ "move-node-to-workspace 10" ]; # run = [ "layout tiling" ];
# } # }
# communications # {
{ # "if".app-id = "com.apple.ActivityMonitor";
"if".app-id = "com.tinyspeck.slackmacgap"; # run = [ "layout floating" ];
run = [ "move-node-to-workspace 9" ]; # }
} # {
{ # "if".app-id = "com.apple.calculator";
"if".app-id = "com.microsoft.teams2"; # run = [ "layout floating" ];
run = [ "move-node-to-workspace 9" ]; # }
} # {
# special app's layout # "if".app-id = "com.apple.finder";
## tiling # run = [ "layout floating" ];
{ # }
"if".app-id = "com.mitchellh.ghostty"; # {
run = [ "layout tiling" ]; # "if".app-id = "com.1password.1password";
} # run = [ "layout floating" ];
## floating # }
{ # {
"if".app-id = "com.renfei.SnippetsLab"; # "if".app-id = "com.chabomakers.Antinote";
run = [ "layout floating" ]; # run = [ "layout floating" ];
} # }
{ # ];
"if".app-id = "com.colliderli.iina"; # };
run = [ "layout tiling" ]; # };
}
{
"if".app-id = "com.apple.ActivityMonitor";
run = [ "layout floating" ];
}
{
"if".app-id = "com.apple.calculator";
run = [ "layout floating" ];
}
{
"if".app-id = "com.apple.finder";
run = [ "layout floating" ];
}
{
"if".app-id = "com.1password.1password";
run = [ "layout floating" ];
}
{
"if".app-id = "com.chabomakers.Antinote";
run = [ "layout floating" ];
}
];
};
};
}; };
} }

View file

@ -65,6 +65,7 @@
marta = mkEnableOption "Enable marta"; marta = mkEnableOption "Enable marta";
valgrind = mkEnableOption "Enable valgrind"; valgrind = mkEnableOption "Enable valgrind";
hammerspoon = mkEnableOption "Enable hammerspoon"; hammerspoon = mkEnableOption "Enable hammerspoon";
aerospace = mkEnableOption "Enable aerospace";
}; };
config = lib.mkMerge [ config = lib.mkMerge [
@ -80,10 +81,11 @@
"homebrew/homebrew-createzap" = inputs.homebrew-createzap; "homebrew/homebrew-createzap" = inputs.homebrew-createzap;
"d12frosted/homebrew-emacs-plus" = inputs.homebrew-emacs-plus; "d12frosted/homebrew-emacs-plus" = inputs.homebrew-emacs-plus;
"brewsci/homebrew-bio" = inputs.homebrew-brewsci-bio; "brewsci/homebrew-bio" = inputs.homebrew-brewsci-bio;
"nikitabobko/tap" = inputs.homebrew-nikitabobko;
# "LouisBrunner/valgrind" = inputs.homebrew-valgrind; # "LouisBrunner/valgrind" = inputs.homebrew-valgrind;
} }
]; ];
mutableTaps = false; # true to enable valgrind mutableTaps = true; # true to enable valgrind
}; };
homebrew = { homebrew = {
enable = true; enable = true;
@ -201,7 +203,7 @@
}) })
(lib.mkIf config.custom.brew.ice { (lib.mkIf config.custom.brew.ice {
homebrew.casks = [ homebrew.casks = [
"jordanbaird-ice" "jordanbaird-ice@beta"
]; ];
}) })
(lib.mkIf config.custom.brew.contexts { (lib.mkIf config.custom.brew.contexts {
@ -382,5 +384,10 @@
"hammerspoon" "hammerspoon"
]; ];
}) })
(lib.mkIf config.custom.brew.aerospace {
homebrew.casks = [
"aerospace"
];
})
]; ];
} }

View file

@ -25,9 +25,11 @@ in
enable = true; enable = true;
# active_color = "0xFFA1EFE4"; # active_color = "0xFFA1EFE4";
# inactive_color = "0xFFd3b58d"; # inactive_color = "0xFFd3b58d";
active_color = "0xFFFFFFFF"; # active_color = "0xFFFFFFFF";
inactive_color = "0xFF000000"; # inactive_color = "0xFF000000";
width = 5.0; active_color = "0xFFFFBE69";
inactive_color = "0xFF007692";
width = 8.0;
}; };
}; };
} }

View file

@ -45,6 +45,7 @@ in
hm.home.packages = with pkgs; [ hm.home.packages = with pkgs; [
sketchybar-app-font sketchybar-app-font
custom.sk-utils
]; ];
hm.xdg.configFile = { hm.xdg.configFile = {

View file

@ -1,5 +1,24 @@
{ {
"nodes": { "nodes": {
"aerospace-scratchpad": {
"inputs": {
"nixpkgs": "nixpkgs",
"utils": "utils"
},
"locked": {
"lastModified": 1764407814,
"narHash": "sha256-IiOWUqodFqzy4PhU6LcziwoJbbFR0AfaOBJDO83/mHM=",
"owner": "cristianoliveira",
"repo": "aerospace-scratchpad",
"rev": "d039cd49e2a15144c9a766509abe1b7f59eb6b04",
"type": "github"
},
"original": {
"owner": "cristianoliveira",
"repo": "aerospace-scratchpad",
"type": "github"
}
},
"brew-src": { "brew-src": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -103,7 +122,7 @@
}, },
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems_2"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1731533236,
@ -141,7 +160,7 @@
}, },
"flake-utils_3": { "flake-utils_3": {
"inputs": { "inputs": {
"systems": "systems_3" "systems": "systems_4"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1731533236,
@ -161,7 +180,7 @@
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs_2",
"zig": "zig", "zig": "zig",
"zon2nix": "zon2nix" "zon2nix": "zon2nix"
}, },
@ -343,6 +362,22 @@
"type": "github" "type": "github"
} }
}, },
"homebrew-nikitabobko": {
"flake": false,
"locked": {
"lastModified": 1764022179,
"narHash": "sha256-OQJ6Wx6Pi61uu46I7xaHpeiTavDQp1ZLVbHJGR1NL20=",
"owner": "nikitabobko",
"repo": "homebrew-tap",
"rev": "80dfd269edca8bc2ec5d83dbd332863cf684f753",
"type": "github"
},
"original": {
"owner": "nikitabobko",
"repo": "homebrew-tap",
"type": "github"
}
},
"homebrew-valgrind": { "homebrew-valgrind": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -364,8 +399,8 @@
"cl-nix-lite": "cl-nix-lite", "cl-nix-lite": "cl-nix-lite",
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_3",
"flake-utils": "flake-utils_2", "flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_3", "nixpkgs": "nixpkgs_4",
"systems": "systems_2", "systems": "systems_3",
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
"locked": { "locked": {
@ -459,20 +494,22 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 315532800, "lastModified": 1747762468,
"narHash": "sha256-sV6pJNzFkiPc6j9Bi9JuHBnWdVhtKB/mHgVmMPvDFlk=", "narHash": "sha256-I8l6r639PrDpEpAFgY64GmuQ+4NK+nxqAoSUnAEKw9E=",
"rev": "82c2e0d6dde50b17ae366d2aa36f224dc19af469", "owner": "NixOS",
"type": "tarball", "repo": "nixpkgs",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre877938.82c2e0d6dde5/nixexprs.tar.xz" "rev": "6bd7ba77ef6015853d67a89bd59f01b2880e9050",
"type": "github"
}, },
"original": { "original": {
"type": "tarball", "owner": "NixOS",
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz" "repo": "nixpkgs",
"type": "github"
} }
}, },
"nixpkgs-firefox-darwin": { "nixpkgs-firefox-darwin": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_6" "nixpkgs": "nixpkgs_7"
}, },
"locked": { "locked": {
"lastModified": 1764291786, "lastModified": 1764291786,
@ -489,6 +526,19 @@
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": {
"lastModified": 315532800,
"narHash": "sha256-sV6pJNzFkiPc6j9Bi9JuHBnWdVhtKB/mHgVmMPvDFlk=",
"rev": "82c2e0d6dde50b17ae366d2aa36f224dc19af469",
"type": "tarball",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre877938.82c2e0d6dde5/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"
}
},
"nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1758360447, "lastModified": 1758360447,
"narHash": "sha256-XDY3A83bclygHDtesRoaRTafUd80Q30D/Daf9KSG6bs=", "narHash": "sha256-XDY3A83bclygHDtesRoaRTafUd80Q30D/Daf9KSG6bs=",
@ -501,7 +551,7 @@
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
} }
}, },
"nixpkgs_3": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1732617236, "lastModified": 1732617236,
"narHash": "sha256-PYkz6U0bSEaEB1al7O1XsqVNeSNS+s3NVclJw7YC43w=", "narHash": "sha256-PYkz6U0bSEaEB1al7O1XsqVNeSNS+s3NVclJw7YC43w=",
@ -517,7 +567,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_4": { "nixpkgs_5": {
"locked": { "locked": {
"lastModified": 1754340878, "lastModified": 1754340878,
"narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=",
@ -533,7 +583,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_5": { "nixpkgs_6": {
"locked": { "locked": {
"lastModified": 1764242076, "lastModified": 1764242076,
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=",
@ -549,7 +599,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_6": { "nixpkgs_7": {
"locked": { "locked": {
"lastModified": 1746683680, "lastModified": 1746683680,
"narHash": "sha256-+5zk+UbG0+GQlKt+gIKm+OhlYvHmkAHFXvf7hl1HDeM=", "narHash": "sha256-+5zk+UbG0+GQlKt+gIKm+OhlYvHmkAHFXvf7hl1HDeM=",
@ -565,7 +615,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_7": { "nixpkgs_8": {
"locked": { "locked": {
"lastModified": 1763806073, "lastModified": 1763806073,
"narHash": "sha256-FHsEKDvfWpzdADWj99z7vBk4D716Ujdyveo5+A048aI=", "narHash": "sha256-FHsEKDvfWpzdADWj99z7vBk4D716Ujdyveo5+A048aI=",
@ -583,6 +633,7 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"aerospace-scratchpad": "aerospace-scratchpad",
"disko": "disko", "disko": "disko",
"ghostty": "ghostty", "ghostty": "ghostty",
"git-hooks": "git-hooks", "git-hooks": "git-hooks",
@ -592,13 +643,14 @@
"homebrew-core": "homebrew-core", "homebrew-core": "homebrew-core",
"homebrew-createzap": "homebrew-createzap", "homebrew-createzap": "homebrew-createzap",
"homebrew-emacs-plus": "homebrew-emacs-plus", "homebrew-emacs-plus": "homebrew-emacs-plus",
"homebrew-nikitabobko": "homebrew-nikitabobko",
"homebrew-valgrind": "homebrew-valgrind", "homebrew-valgrind": "homebrew-valgrind",
"mac-app-util": "mac-app-util", "mac-app-util": "mac-app-util",
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nix-homebrew": "nix-homebrew", "nix-homebrew": "nix-homebrew",
"nix-index-database": "nix-index-database", "nix-index-database": "nix-index-database",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_5", "nixpkgs": "nixpkgs_6",
"nixpkgs-firefox-darwin": "nixpkgs-firefox-darwin", "nixpkgs-firefox-darwin": "nixpkgs-firefox-darwin",
"sops-nix": "sops-nix", "sops-nix": "sops-nix",
"treefmt-nix": "treefmt-nix_2", "treefmt-nix": "treefmt-nix_2",
@ -663,6 +715,21 @@
} }
}, },
"systems_2": { "systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": { "locked": {
"lastModified": 1689347925, "lastModified": 1689347925,
"narHash": "sha256-ozenz5bFe1UUqOn7f60HRmgc01BgTGIKZ4Xl+HbocGQ=", "narHash": "sha256-ozenz5bFe1UUqOn7f60HRmgc01BgTGIKZ4Xl+HbocGQ=",
@ -677,7 +744,7 @@
"type": "github" "type": "github"
} }
}, },
"systems_3": { "systems_4": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
@ -694,7 +761,7 @@
}, },
"treefmt-nix": { "treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_5"
}, },
"locked": { "locked": {
"lastModified": 1755934250, "lastModified": 1755934250,
@ -730,10 +797,28 @@
"type": "github" "type": "github"
} }
}, },
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"yazi": { "yazi": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_3", "flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_7", "nixpkgs": "nixpkgs_8",
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
}, },
"locked": { "locked": {
@ -802,7 +887,7 @@
}, },
"zon2nix": { "zon2nix": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1758405547, "lastModified": 1758405547,

View file

@ -40,8 +40,11 @@
homebrew-brewsci-bio.flake = false; homebrew-brewsci-bio.flake = false;
homebrew-valgrind.url = "github:LouisBrunner/homebrew-valgrind"; homebrew-valgrind.url = "github:LouisBrunner/homebrew-valgrind";
homebrew-valgrind.flake = false; homebrew-valgrind.flake = false;
homebrew-nikitabobko.url = "github:nikitabobko/homebrew-tap";
homebrew-nikitabobko.flake = false;
# tools # tools
aerospace-scratchpad.url = "github:cristianoliveira/aerospace-scratchpad";
yazi.url = "github:sxyazi/yazi"; yazi.url = "github:sxyazi/yazi";
}; };

View file

@ -5,10 +5,10 @@
{ {
custom = { custom = {
gui = { gui = {
aerospace.enable = false; aerospace.enable = true;
sketchybar.enable = true; sketchybar.enable = true;
jankyborders.enable = true; jankyborders.enable = true;
yabai.enable = true; yabai.enable = false;
}; };
brew = { brew = {
zen-browser = false; zen-browser = false;
@ -64,6 +64,7 @@
marta = true; marta = true;
valgrind = true; valgrind = true;
hammerspoon = true; hammerspoon = true;
aerospace = true;
}; };
}; };