summaryrefslogtreecommitdiff
path: root/pkgs
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-06-17 15:14:45 -0400
committerFreya Murphy <freya@freyacat.org>2025-06-17 15:14:45 -0400
commit1173df26fd78fdd59679645004847237ed7a0a54 (patch)
treeb75e6bd3ee1a878b1a3e74d94fb9ea0bb94c14a7 /pkgs
parentadd upowerd (diff)
downloaddotfiles-nix-1173df26fd78fdd59679645004847237ed7a0a54.tar.gz
dotfiles-nix-1173df26fd78fdd59679645004847237ed7a0a54.tar.bz2
dotfiles-nix-1173df26fd78fdd59679645004847237ed7a0a54.zip
add astal package, update flake to support packages
Diffstat (limited to 'pkgs')
-rw-r--r--pkgs/astal/default.nix38
-rw-r--r--pkgs/astal/src/init.lua16
-rw-r--r--pkgs/astal/src/lib.lua78
-rw-r--r--pkgs/astal/src/style/style.scss56
-rw-r--r--pkgs/astal/src/style/theme.scss32
-rw-r--r--pkgs/astal/src/style/widget/bar.scss48
-rw-r--r--pkgs/astal/src/style/widget/corners.scss9
-rw-r--r--pkgs/astal/src/widget/bar/audio.lua20
-rw-r--r--pkgs/astal/src/widget/bar/battery.lua21
-rw-r--r--pkgs/astal/src/widget/bar/date.lua18
-rw-r--r--pkgs/astal/src/widget/bar/focusedClient.lua29
-rw-r--r--pkgs/astal/src/widget/bar/init.lua44
-rw-r--r--pkgs/astal/src/widget/bar/tray.lua34
-rw-r--r--pkgs/astal/src/widget/bar/wifi.lua24
-rw-r--r--pkgs/astal/src/widget/bar/workspaces.lua28
-rw-r--r--pkgs/astal/src/widget/corners.lua19
-rw-r--r--pkgs/default.nix12
17 files changed, 526 insertions, 0 deletions
diff --git a/pkgs/astal/default.nix b/pkgs/astal/default.nix
new file mode 100644
index 0000000..73ada9c
--- /dev/null
+++ b/pkgs/astal/default.nix
@@ -0,0 +1,38 @@
+{
+ pkgs,
+ inputs,
+ system,
+ runCommand,
+ dart-sass,
+ ...
+}:
+
+let
+ apkgs = inputs.astal.packages.${system};
+ scss = "${dart-sass}/bin/sass";
+in
+inputs.astal.lib.mkLuaPackage {
+ pkgs = pkgs // {
+ # use luajit
+ lua = pkgs.luajit;
+ };
+ src = runCommand "src" {} ''
+ mkdir -p $out
+ cp -r ${./src}/{*.lua,widget} $out/
+ cp -r ${./src}/style/* .
+ cat theme.scss style.scss widget/* > main.scss
+ ${scss} main.scss $out/main.css
+ '';
+ name = "astal";
+ extraPackages = (with apkgs; [
+ battery
+ hyprland
+ mpris
+ network
+ notifd
+ tray
+ wireplumber
+ ]) ++ (with pkgs; [
+ networkmanager
+ ]);
+}
diff --git a/pkgs/astal/src/init.lua b/pkgs/astal/src/init.lua
new file mode 100644
index 0000000..b350fbf
--- /dev/null
+++ b/pkgs/astal/src/init.lua
@@ -0,0 +1,16 @@
+local astal = require("astal")
+local App = require("astal.gtk3.app")
+local lib = require("lib")
+
+local Bar = require("widget.bar")
+local Corners = require("widget.corners")
+
+App:start({
+ css = lib.src("main.css"),
+ main = function()
+ for _, mon in pairs(App.monitors) do
+ Bar(mon)
+ Corners(mon)
+ end
+ end,
+})
diff --git a/pkgs/astal/src/lib.lua b/pkgs/astal/src/lib.lua
new file mode 100644
index 0000000..93f4bc1
--- /dev/null
+++ b/pkgs/astal/src/lib.lua
@@ -0,0 +1,78 @@
+local Variable = require("astal").Variable
+
+local lib
+
+lib = {
+ --- get path to file in astal source
+ src = function(path)
+ local str = debug.getinfo(2, "S").source:sub(2)
+ local src = str:match("(.*/)") or str:match("(.*\\)") or "./"
+ return src .. path
+ end,
+
+ --- map an array with a function
+ map = function(array, func)
+ local new_arr = {}
+ for i, v in ipairs(array) do
+ new_arr[i] = func(v, i)
+ end
+ return new_arr
+ end,
+
+ --- filter an array with a function
+ filter = function(array, func)
+ local new_arr = {}
+ for i, v in ipairs(array) do
+ if func(v, i) then
+ new_arr[i] = v
+ end
+ end
+ return new_arr
+ end,
+
+ --- sort an array of object on a key
+ sort = function(array, func)
+
+ -- default func to sort on attr 'id'
+ if not func then
+ func = 'id'
+ end
+
+ -- make function if just provided with attribute
+ if type(func) ~= 'function' then
+ local key = func
+ func = function(a, b) return a[key] < b[key] end
+ end
+
+ -- copy to new array
+ local new_arr = {}
+ for i, v in ipairs(array) do
+ new_arr[i] = v
+ end
+
+ -- sort and return
+ table.sort(new_arr, func)
+ return new_arr
+ end,
+
+ --- returns length of table
+ count = function(array)
+ if not array then
+ return 0
+ else
+ return #array
+ end
+ end,
+
+ --- returns if a table is empty
+ empty = function(array)
+ return lib.count(array) == 0
+ end,
+
+ --- negates value
+ neg = function(val)
+ return not val
+ end,
+}
+
+return lib
diff --git a/pkgs/astal/src/style/style.scss b/pkgs/astal/src/style/style.scss
new file mode 100644
index 0000000..77c8b36
--- /dev/null
+++ b/pkgs/astal/src/style/style.scss
@@ -0,0 +1,56 @@
+@use "sass:color";
+@use "sass:math";
+
+@import "./theme";
+
+* {
+ all: unset;
+}
+
+window {
+ color: $text;
+ font-family: $font-name;
+}
+
+button {
+ color: $text;
+ background: $surface-bg;
+
+ &:hover {
+ color: $hover;
+ background: $hover-bg;
+ }
+
+ &.primary {
+ color: $primary;
+ background: $primary-bg;
+ }
+}
+
+menu {
+ background: $bg;
+ padding: $inner-gap 0;
+ border-radius: $outer-radius;
+
+ menuitem {
+ color: $text;
+ margin: $inner-gap $outer-gap;
+ padding: $inner-gap;
+ border-radius: $inner-radius;
+
+ &:hover,
+ &:selected {
+ background: $surface-bg;
+ }
+
+ &:disabled {
+ color: $subtext;
+ }
+ }
+
+ separator {
+ background-color: $surface-bg;
+ min-height: 1px;
+ margin: $inner-gap 0;
+ }
+}
diff --git a/pkgs/astal/src/style/theme.scss b/pkgs/astal/src/style/theme.scss
new file mode 100644
index 0000000..2af74f5
--- /dev/null
+++ b/pkgs/astal/src/style/theme.scss
@@ -0,0 +1,32 @@
+
+$text: #cdd6f4;
+$subtext: #a6adc8;
+
+$bg: #1e1e2e;
+$surface-bg: #313244;
+
+$hover: $text;
+$hover-bg: #6c7086;
+
+$primary: $bg;
+$primary-bg: #89b4fa;
+
+$success: #a6e3a1;
+$success-bg: $bg;
+
+$warning: #f9e2af;
+$warning-bg: $bg;
+
+$error: #f38ba8;
+$error-bg: $bg;
+
+$border: 2px;
+
+$inner-radius: 4px;
+$outer-radius: 8px;
+
+$inner-gap: 3px;
+$outer-gap: 10px;
+
+$font-name: "JetBrains Mono", "monospace";
+$font-size: 14px;
diff --git a/pkgs/astal/src/style/widget/bar.scss b/pkgs/astal/src/style/widget/bar.scss
new file mode 100644
index 0000000..01e73ce
--- /dev/null
+++ b/pkgs/astal/src/style/widget/bar.scss
@@ -0,0 +1,48 @@
+
+.bar {
+ background: $bg;
+
+ .workspaces {
+ margin: $inner-gap $outer-gap;
+
+ .workspace {
+ margin: $inner-gap;
+ border-radius: $inner-radius;
+ min-width: $font-size + $outer-gap;
+ min-height: $font-size + $outer-gap;
+ font-weight: bold;
+ }
+ }
+
+ .right {
+ margin: $inner-gap $outer-gap;
+
+ .wifi,
+ .audio,
+ .battery,
+ .tray {
+ margin: $inner-gap $outer-gap;
+ margin-right: 0px;
+ background: $surface-bg;
+ border-radius: $inner-radius;
+ padding: 0px $outer-gap;
+
+ icon {
+ margin-right: $inner-gap;
+ }
+
+ }
+
+ .tray {
+ padding-right: 0;
+
+ icon {
+ margin-right: $outer-gap;
+ }
+
+ .menubtn:hover {
+ background: transparent;
+ }
+ }
+ }
+}
diff --git a/pkgs/astal/src/style/widget/corners.scss b/pkgs/astal/src/style/widget/corners.scss
new file mode 100644
index 0000000..53cdb9b
--- /dev/null
+++ b/pkgs/astal/src/style/widget/corners.scss
@@ -0,0 +1,9 @@
+
+.corners {
+ $radius: $outer-radius + $outer-gap;
+
+ box {
+ box-shadow: 0 0 0 $radius $bg;
+ border-radius: $radius $radius 0 0;
+ }
+}
diff --git a/pkgs/astal/src/widget/bar/audio.lua b/pkgs/astal/src/widget/bar/audio.lua
new file mode 100644
index 0000000..c1934f9
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/audio.lua
@@ -0,0 +1,20 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Wp = astal.require("AstalWp")
+local bind = astal.bind
+
+return function()
+ local speaker = Wp.get_default().audio.default_speaker
+
+ return Widget.Box({
+ class_name = "audio",
+ Widget.Icon({
+ icon = bind(speaker, "volume-icon"),
+ }),
+ Widget.Label({
+ label = bind(speaker, "volume"):as(function(p)
+ return tostring(math.floor(p * 100)) .. '%'
+ end)
+ }),
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/battery.lua b/pkgs/astal/src/widget/bar/battery.lua
new file mode 100644
index 0000000..d13143a
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/battery.lua
@@ -0,0 +1,21 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Battery = astal.require("AstalBattery")
+local bind = astal.bind
+
+return function()
+ local bat = Battery.get_default()
+
+ return Widget.Box({
+ class_name = "battery",
+ visible = bind(bat, "is-present"),
+ Widget.Icon({
+ icon = bind(bat, "battery-icon-name"),
+ }),
+ Widget.Label({
+ label = bind(bat, "percentage"):as(function(p)
+ return tostring(math.floor(p * 100)) .. '%'
+ end)
+ }),
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/date.lua b/pkgs/astal/src/widget/bar/date.lua
new file mode 100644
index 0000000..b64d8bb
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/date.lua
@@ -0,0 +1,18 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Variable = astal.Variable
+local GLib = astal.require("GLib")
+
+local format = "%Y-%m-%d %a %H:%M:%S"
+local date = Variable(""):poll(
+ 1000, function()
+ return GLib.DateTime.new_now_local():format(format)
+ end
+);
+
+return function()
+ return Widget.Label({
+ class_name = "date",
+ label = date(),
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/focusedClient.lua b/pkgs/astal/src/widget/bar/focusedClient.lua
new file mode 100644
index 0000000..329cc4e
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/focusedClient.lua
@@ -0,0 +1,29 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Hyprland = astal.require("AstalHyprland")
+local bind = astal.bind
+
+local hypr = Hyprland.get_default()
+
+function Client(client)
+ -- sanity check
+ if not client then
+ return nil
+ end
+
+ return Widget.Label({
+ ellipsize = "END",
+ max_width_chars = 50,
+ label = bind(client, "title"):as(tostring),
+ })
+end
+
+return function()
+ local focused = bind(hypr, "focused-client")
+
+ return Widget.Box({
+ class_name = "focusedClient",
+ visible = focused,
+ focused:as(Client)
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/init.lua b/pkgs/astal/src/widget/bar/init.lua
new file mode 100644
index 0000000..038ac90
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/init.lua
@@ -0,0 +1,44 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+
+local Workspaces = require("widget.bar.workspaces")
+local FocusedClient = require("widget.bar.focusedClient")
+local Date = require("widget.bar.date")
+local WiFi = require("widget.bar.wifi")
+local Audio = require("widget.bar.audio")
+local Battery = require("widget.bar.battery")
+local Tray = require("widget.bar.tray")
+
+return function(gdkmonitor)
+ local Anchor = astal.require('Astal').WindowAnchor
+
+ return Widget.Window({
+ class_name = "bar",
+ gdkmonitor = gdkmonitor,
+ anchor = Anchor.TOP + Anchor.LEFT + Anchor.RIGHT,
+ exclusivity = "EXCLUSIVE",
+ Widget.CenterBox({
+ Widget.Box({
+ class_name = "left",
+ halign = "START",
+ hexpand = true,
+ Workspaces(),
+ FocusedClient(),
+ }),
+ Widget.Box({
+ class_name = "center",
+ hexpand = true,
+ Date(),
+ }),
+ Widget.Box({
+ class_name = "right",
+ halign = "END",
+ hexpand = true,
+ WiFi(),
+ Audio(),
+ Battery(),
+ Tray(),
+ }),
+ })
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/tray.lua b/pkgs/astal/src/widget/bar/tray.lua
new file mode 100644
index 0000000..9046494
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/tray.lua
@@ -0,0 +1,34 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Tray = astal.require("AstalTray")
+local lib = require("lib")
+local bind = astal.bind
+
+function Item(item)
+ return Widget.MenuButton({
+ class_name = "menubtn",
+ tooltip_markup = bind(item, "tooltip_markup"),
+ use_popover = false,
+ menu_model = bind(item, "menu-model"),
+ action_group = bind(item, "action-group"):as(
+ function(ag) return { "dbusmenu", ag } end
+ ),
+ Widget.Icon({
+ gicon = bind(item, "gicon"),
+ }),
+ })
+end
+
+function Items(items)
+ return lib.map(items, Item)
+end
+
+return function()
+ local tray = Tray.get_default()
+
+ return Widget.Box({
+ class_name = "tray",
+ visible = bind(tray, "items"):as(lib.empty):as(lib.neg),
+ bind(tray, "items"):as(Items)
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/wifi.lua b/pkgs/astal/src/widget/bar/wifi.lua
new file mode 100644
index 0000000..7a293a0
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/wifi.lua
@@ -0,0 +1,24 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Network = astal.require("AstalNetwork")
+local bind = astal.bind
+
+return function()
+ local network = Network.get_default()
+ local wifi = bind(network, "wifi")
+
+ return Widget.Box({
+ class_name = "wifi",
+ visible = wifi,
+ wifi:as(function(wifi)
+ return Widget.Box({
+ Widget.Icon({
+ icon = bind(wifi, "icon-name"),
+ }),
+ Widget.Label({
+ label = bind(wifi, "ssid"),
+ }),
+ })
+ end),
+ })
+end
diff --git a/pkgs/astal/src/widget/bar/workspaces.lua b/pkgs/astal/src/widget/bar/workspaces.lua
new file mode 100644
index 0000000..8bc1785
--- /dev/null
+++ b/pkgs/astal/src/widget/bar/workspaces.lua
@@ -0,0 +1,28 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+local Hyprland = astal.require("AstalHyprland")
+local lib = require('lib')
+local bind = astal.bind
+
+local hypr = Hyprland.get_default()
+
+function Workspace(ws)
+ return Widget.Button({
+ class_name = bind(hypr, "focused-workspace"):as(function(fw)
+ return "workspace " .. (fw == ws and "primary" or "")
+ end),
+ on_clicked = function() ws:focus() end,
+ label = ws.id,
+ })
+end
+
+function Workspaces(wss)
+ return lib.map(lib.sort(wss, 'id'), Workspace)
+end
+
+return function()
+ return Widget.Box({
+ class_name = "workspaces",
+ bind(hypr, "workspaces"):as(Workspaces)
+ })
+end
diff --git a/pkgs/astal/src/widget/corners.lua b/pkgs/astal/src/widget/corners.lua
new file mode 100644
index 0000000..d1a7755
--- /dev/null
+++ b/pkgs/astal/src/widget/corners.lua
@@ -0,0 +1,19 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+
+return function(gdkmonitor)
+ local Anchor = astal.require('Astal').WindowAnchor
+
+ return Widget.Window({
+ class_name = "corners",
+ gdkmonitor = gdkmonitor,
+ anchor = Anchor.TOP + Anchor.BOTTOM + Anchor.LEFT + Anchor.RIGHT,
+ exclusivity = "EXCLUSIVE",
+ setup = function(self)
+ self.click_through = true
+ end,
+ Widget.Box({
+ expand = true,
+ })
+ })
+end
diff --git a/pkgs/default.nix b/pkgs/default.nix
new file mode 100644
index 0000000..042fc16
--- /dev/null
+++ b/pkgs/default.nix
@@ -0,0 +1,12 @@
+{ pkgs, inputs, system, ... }:
+
+let
+ build = (path: pkgs.callPackage path {
+ inherit pkgs;
+ inherit inputs;
+ inherit system;
+ });
+in
+{
+ astal = build ./astal;
+}