summaryrefslogtreecommitdiff
path: root/pkgs/astal/src
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/astal/src')
-rw-r--r--pkgs/astal/src/init.lua2
-rw-r--r--pkgs/astal/src/lib.lua67
-rw-r--r--pkgs/astal/src/style/style.scss1
-rw-r--r--pkgs/astal/src/style/widget/deck.scss89
-rw-r--r--pkgs/astal/src/widget/bar/tray.lua2
-rw-r--r--pkgs/astal/src/widget/deck/init.lua18
-rw-r--r--pkgs/astal/src/widget/deck/notifications.lua136
7 files changed, 310 insertions, 5 deletions
diff --git a/pkgs/astal/src/init.lua b/pkgs/astal/src/init.lua
index b350fbf..5bdfb03 100644
--- a/pkgs/astal/src/init.lua
+++ b/pkgs/astal/src/init.lua
@@ -4,6 +4,7 @@ local lib = require("lib")
local Bar = require("widget.bar")
local Corners = require("widget.corners")
+local Deck = require("widget.deck")
App:start({
css = lib.src("main.css"),
@@ -11,6 +12,7 @@ App:start({
for _, mon in pairs(App.monitors) do
Bar(mon)
Corners(mon)
+ Deck(mon)
end
end,
})
diff --git a/pkgs/astal/src/lib.lua b/pkgs/astal/src/lib.lua
index 93f4bc1..992c0af 100644
--- a/pkgs/astal/src/lib.lua
+++ b/pkgs/astal/src/lib.lua
@@ -1,4 +1,7 @@
+local astal = require("astal")
local Variable = require("astal").Variable
+local Astal = require("astal.gtk3").Astal
+local GLib = astal.require("GLib")
local lib
@@ -55,12 +58,31 @@ lib = {
return new_arr
end,
- --- returns length of table
- count = function(array)
- if not array then
+ --- returns if value is an array
+ is_array = function(val)
+ return type(val) == 'table'
+ end,
+
+ --- returns if value is an string
+ is_string = function(val)
+ return type(val) == 'string'
+ end,
+
+ --- returns if value is nil
+ is_nil = function(val)
+ return val == nil
+ end,
+
+ --- returns length of table or string
+ count = function(val)
+ if lib.is_array(val) then
+ return #val
+ elseif lib.is_string(val) then
+ return val:len()
+ elseif lib.is_nil(val) then
return 0
else
- return #array
+ return nil
end
end,
@@ -73,6 +95,43 @@ lib = {
neg = function(val)
return not val
end,
+
+ --- better truthy function
+ is_true = function(val)
+ -- zero is false
+ if val == 0 then
+ return false
+ end
+
+ -- empty array or string is false
+ if lib.empty(val) then
+ return false
+ end
+
+ -- default truthyness
+ return val and true or false
+ end,
+
+ --- better fasly function
+ is_false = function(val)
+ return not lib.is_true(val)
+ end,
+
+ --- checks if a file exists
+ file_exists = function(path)
+ return GLib.file_test(path, "EXISTS")
+ end,
+
+ --- checks if a string is an icon
+ is_icon = function(icon)
+ return Astal.Icon.lookup_icon(icon) ~= nil
+ end,
+
+ --- formats a time
+ time = function(time, format)
+ format = format or "%H:%M"
+ return GLib.DateTime.new_from_unix_local(time):format(format)
+ end,
}
return lib
diff --git a/pkgs/astal/src/style/style.scss b/pkgs/astal/src/style/style.scss
index 7be2b2f..0c66051 100644
--- a/pkgs/astal/src/style/style.scss
+++ b/pkgs/astal/src/style/style.scss
@@ -1,3 +1,4 @@
+@use "sass:string";
@use "sass:color";
@use "sass:math";
diff --git a/pkgs/astal/src/style/widget/deck.scss b/pkgs/astal/src/style/widget/deck.scss
new file mode 100644
index 0000000..cd926f0
--- /dev/null
+++ b/pkgs/astal/src/style/widget/deck.scss
@@ -0,0 +1,89 @@
+
+@function gtkalpha($c, $a) {
+ @return string.unquote("alpha(#{$c},#{$a})");
+}
+
+$deck-scale: $font-size * 5;
+
+.deck {
+
+ > box {
+ padding: $outer-gap;
+ }
+
+ .notification {
+ > box {
+ color: $fg;
+ background: $bg;
+ border-radius: $outer-radius;
+ margin-bottom: $outer-gap;
+ min-width: $deck-scale * 5;
+ }
+ }
+}
+
+.notification {
+ > box {
+ &.critical {
+ .app-name {
+ color: gtkalpha($error, .8);
+ }
+
+ .app-icon {
+ color: gtkalpha($error, .6);
+ }
+ }
+ }
+
+ .header {
+ padding: $outer-gap;
+ color: gtkalpha($fg, 0.5);
+
+ .app-icon {
+ margin-left: $inner-gap;
+ margin-right: $outer-gap;
+ }
+
+ .app-name {
+ margin-right: $inner-gap;
+ font-weight: bold;
+
+ &:first-child {
+ margin-left: $outer-gap;
+ }
+ }
+
+ .time {
+ margin: 0 $outer-gap;
+ }
+
+ button {
+ padding: $inner-gap;
+ border-radius: $inner-radius;
+ min-width: 0;
+ min-height: 0;
+ }
+ }
+
+ separator {
+ margin: 0 $outer-gap;
+ background: gtkalpha($fg, .1);
+ }
+
+ .content {
+ margin: $outer-gap;
+
+ .body {
+ color: gtkalpha($fg, 0.8);
+ }
+
+ .image {
+ margin-right: $outer-gap;
+ border-radius: $inner-gap;
+ min-width: $deck-scale;
+ min-height: $deck-scale;
+ background-size: cover;
+ background-position: center;
+ }
+ }
+}
diff --git a/pkgs/astal/src/widget/bar/tray.lua b/pkgs/astal/src/widget/bar/tray.lua
index 9046494..f0460b9 100644
--- a/pkgs/astal/src/widget/bar/tray.lua
+++ b/pkgs/astal/src/widget/bar/tray.lua
@@ -28,7 +28,7 @@ return function()
return Widget.Box({
class_name = "tray",
- visible = bind(tray, "items"):as(lib.empty):as(lib.neg),
+ visible = bind(tray, "items"):as(lib.is_true),
bind(tray, "items"):as(Items)
})
end
diff --git a/pkgs/astal/src/widget/deck/init.lua b/pkgs/astal/src/widget/deck/init.lua
new file mode 100644
index 0000000..0df5bb4
--- /dev/null
+++ b/pkgs/astal/src/widget/deck/init.lua
@@ -0,0 +1,18 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3.widget")
+
+local Notifications = require("widget.deck.notifications")
+
+return function(gdkmonitor)
+ local Anchor = astal.require('Astal').WindowAnchor
+
+ return Widget.Window({
+ class_name = "deck",
+ gdkmonitor = gdkmonitor,
+ anchor = Anchor.TOP + Anchor.RIGHT,
+ Widget.Box({
+ vertical = true,
+ Notifications(),
+ }),
+ })
+end
diff --git a/pkgs/astal/src/widget/deck/notifications.lua b/pkgs/astal/src/widget/deck/notifications.lua
new file mode 100644
index 0000000..e40a815
--- /dev/null
+++ b/pkgs/astal/src/widget/deck/notifications.lua
@@ -0,0 +1,136 @@
+local astal = require("astal")
+local Widget = require("astal.gtk3").Widget
+local Gtk = require("astal.gtk3").Gtk
+local Variable = require("astal").Variable
+local Notifd = astal.require("AstalNotifd")
+local lib = require("lib")
+local bind = astal.bind
+local timeout = astal.timeout
+
+local TIMEOUT_DELAY = 5000
+
+local notifd = Notifd.get_default()
+local notifs = Variable({})
+local map = {}
+
+function update()
+ local arr = {}
+ for id,_ in pairs(map) do
+ table.insert(arr, id)
+ end
+ notifs:set(arr)
+end
+
+function set(_, id)
+ map[id] = true
+ update()
+end
+
+function delete(id)
+ map[id] = nil
+ update()
+end
+
+notifd.on_notified = set
+
+function Header(notif)
+ local show_icon = lib.is_true(notif.app_icon) or
+ lib.is_true(notif.desktop_entry)
+
+ return Widget.Box({
+ class_name = "header",
+ show_icon and Widget.Icon({
+ class_name = "app-icon",
+ icon = notif.app_icon or notif.desktop_entry,
+ }),
+ Widget.Label({
+ class_name = "app-name",
+ halign = "START",
+ ellipsize = "END",
+ label = notif.app_name or "",
+ }),
+ Widget.Label({
+ class_name = "time",
+ hexpand = true,
+ halign = "END",
+ label = lib.time(notif.time),
+ }),
+ Widget.Button({
+ on_clicked = function() delete(notif.id) end,
+ Widget.Icon({ icon = "window-close-symbolic" }),
+ }),
+ })
+end
+
+function Content(notif)
+ return Widget.Box({
+ class_name = "content",
+ (notif.image and lib.file_exists(notif.image)) and Widget.Box({
+ valign = "START",
+ class_name = "image",
+ css = string.format("background-image: url('%s')", notif.image),
+ }),
+ (notif.image and lib.is_icon(notif.image)) and Widget.Box({
+ valign = "START",
+ class_name = "icon-image",
+ Widget.Icon({
+ icon = notif.image,
+ hexpand = true,
+ vexpand = true,
+ halign = "CENTER",
+ valign = "CENTER",
+ }),
+ }),
+ Widget.Box({
+ vertical = true,
+ Widget.Label({
+ class_name = "summary",
+ halign = "START",
+ xalign = 0,
+ ellipsize = "END",
+ label = notif.summary,
+ }),
+ Widget.Label({
+ class_name = "body",
+ wrap = true,
+ use_markup = true,
+ halign = "START",
+ xalign = 0,
+ justify = "FILL",
+ label = notif.body,
+ }),
+ }),
+ })
+end
+
+function Notification(id)
+ local notif = notifd:get_notification(id)
+
+ local function destroy()
+ delete(id)
+ end
+
+ local function setup()
+ timeout(TIMEOUT_DELAY, destroy)
+ end
+
+ return Widget.EventBox({
+ class_name = "notification",
+ setup = setup,
+ on_hover_lost = destroy,
+ Widget.Box({
+ vertical = true,
+ Header(notif),
+ Gtk.Separator({ visible = true }),
+ Content(notif),
+ }),
+ })
+end
+
+function Notifications(ids)
+ return lib.map(ids, Notification)
+end
+
+return function()
+ return bind(notifs):as(Notifications)
+end