summaryrefslogtreecommitdiff
path: root/examples/lua
diff options
context:
space:
mode:
Diffstat (limited to 'examples/lua')
-rw-r--r--examples/lua/notification-popups/README.md14
-rw-r--r--examples/lua/notification-popups/init.lua21
-rw-r--r--examples/lua/notification-popups/lib.lua52
-rw-r--r--examples/lua/notification-popups/style.scss69
-rw-r--r--examples/lua/notification-popups/widget/notifications.lua125
5 files changed, 281 insertions, 0 deletions
diff --git a/examples/lua/notification-popups/README.md b/examples/lua/notification-popups/README.md
new file mode 100644
index 0000000..bcc6bba
--- /dev/null
+++ b/examples/lua/notification-popups/README.md
@@ -0,0 +1,14 @@
+# Simple Bar Example
+
+![simple-bar](https://github.com/user-attachments/assets/a306c864-56b7-44c4-8820-81f424f32b9b)
+
+A simple bar for Hyprland using
+
+- [Audio library](https://aylur.github.io/astal/guide/libraries/audio).
+- [Battery library](https://aylur.github.io/astal/guide/libraries/battery).
+- [Hyprland library](https://aylur.github.io/astal/guide/libraries/hyprland).
+- [Mpris library](https://aylur.github.io/astal/guide/libraries/mpris).
+- [Network library](https://aylur.github.io/astal/guide/libraries/network).
+- [Tray library](https://aylur.github.io/astal/guide/libraries/tray).
+- [WirePlumber library](https://aylur.github.io/astal/guide/libraries/wireplumber).
+- [dart-sass](https://sass-lang.com/dart-sass/) as the css precompiler
diff --git a/examples/lua/notification-popups/init.lua b/examples/lua/notification-popups/init.lua
new file mode 100644
index 0000000..ffa910c
--- /dev/null
+++ b/examples/lua/notification-popups/init.lua
@@ -0,0 +1,21 @@
+local astal = require("astal")
+local Notify = astal.require("Notify")
+local timeout = astal.timeout
+local App = astal.App
+
+local Notifications = require("widget.notifications")
+local src = require("lib").src
+
+local scss = src("style.scss")
+local css = "/tmp/style.css"
+
+astal.exec("sass " .. scss .. " " .. css)
+
+App:start({
+ css = css,
+ main = function()
+ for _, mon in pairs(App.monitors) do
+ Notifications(mon)
+ end
+ end,
+})
diff --git a/examples/lua/notification-popups/lib.lua b/examples/lua/notification-popups/lib.lua
new file mode 100644
index 0000000..2ae71a9
--- /dev/null
+++ b/examples/lua/notification-popups/lib.lua
@@ -0,0 +1,52 @@
+local Variable = require("astal").Variable
+local astal = require("astal")
+local Gtk = astal.Gtk
+
+local M = {}
+
+function M.src(path)
+ local str = debug.getinfo(2, "S").source:sub(2)
+ local src = str:match("(.*/)") or str:match("(.*\\)") or "./"
+ return src .. path
+end
+
+---@generic T, R
+---@param arr T[]
+---@param func fun(T, integer): R
+---@return R[]
+function M.map(arr, func)
+ local new_arr = {}
+ for i, v in ipairs(arr) do
+ new_arr[i] = func(v, i)
+ end
+ return new_arr
+end
+
+---@param name string
+---@param size? 16 | 32 | 64 | 128 | 256 | 512 | number
+function M.lookup_icon(name, size)
+ if not name or #name == 0 then
+ return
+ end
+ size = size or 256
+
+ local theme = Gtk.IconTheme.get_default()
+ local icon_info, path
+
+ for _, n in ipairs({
+ name,
+ string.lower(name),
+ string.upper(name),
+ }) do
+ icon_info = theme:lookup_icon(n, size, "USE_BUILTIN")
+
+ if icon_info then
+ return icon_info
+ end
+ end
+ return false
+end
+
+M.date = Variable(""):poll(1000, "date")
+
+return M
diff --git a/examples/lua/notification-popups/style.scss b/examples/lua/notification-popups/style.scss
new file mode 100644
index 0000000..8eb764a
--- /dev/null
+++ b/examples/lua/notification-popups/style.scss
@@ -0,0 +1,69 @@
+$bg: #212223;
+$fg: #f1f1f1;
+$accent: #378df7;
+$radius: 7px;
+
+window.notification-popups {
+ box.notifications {
+ padding: 0.5em;
+ }
+}
+
+.icon {
+ min-width: 68px;
+ min-height: 68px;
+ margin-right: 1em;
+}
+
+.icon {
+ icon {
+ font-size: 58px;
+ margin: 5px;
+ color: $fg;
+ }
+ box {
+ min-width: 68px;
+ min-height: 68px;
+ border-radius: $radius;
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+ }
+}
+
+.notification {
+ min-width: 350px;
+ border-radius: 11px;
+ padding: 1em;
+ margin: 0.5em;
+ border: 1px solid transparentize($fg, 0.9);
+ background-color: $bg;
+
+ &.critical {
+ border: 1px solid $accent;
+ }
+
+ .title {
+ color: $fg;
+ font-size: 1.4em;
+ }
+
+ .body {
+ color: transparentize($fg, 0.4);
+ }
+
+ .actions {
+ .action-button {
+ margin: 0 0.4em;
+ margin-top: 0.8em;
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+}
diff --git a/examples/lua/notification-popups/widget/notifications.lua b/examples/lua/notification-popups/widget/notifications.lua
new file mode 100644
index 0000000..4704c22
--- /dev/null
+++ b/examples/lua/notification-popups/widget/notifications.lua
@@ -0,0 +1,125 @@
+local astal = require("astal")
+local Widget = astal.Widget
+local GLib = astal.GLib
+local bind = astal.bind
+local timeout = astal.timeout
+
+local map = require("lib").map
+local lookup_icon = require("lib").lookup_icon
+
+local Notifd = astal.require("AstalNotifd")
+local notifd = Notifd.get_default()
+
+local NOTIFICATION_TIMEOUTMS = 5000
+
+local function NotificationIcon(n)
+ local icon = "dialog-information-symbolic"
+
+ if n.app_icon and GLib.file_test(n.app_icon, "EXISTS") then
+ return Widget.Box({ css = string.format('background-image: url("%s");', n.app_icon) })
+ elseif n.app_icon and lookup_icon(n.app_icon) then
+ icon = n.app_icon
+ elseif n.app_name and lookup_icon(n.app_name) then
+ icon = n.app_name
+ end
+
+ return Widget.Icon({
+ icon = icon,
+ })
+end
+
+local function Notification(n)
+ local icon = Widget.Box({
+ valign = "START",
+ class_name = "icon",
+ NotificationIcon(n),
+ })
+
+ local title = Widget.Label({
+ class_name = "title",
+ xalign = 0,
+ justify = "LEFT",
+ hexpand = true,
+ max_width_chars = 24,
+ wrap = true,
+ ellipsize = "END",
+ use_markup = true,
+ label = n.summary,
+ })
+
+ local body = Widget.Label({
+ class_name = "body",
+ hexpand = true,
+ use_markup = true,
+ xalign = 0,
+ justify = "LEFT",
+ wrap = true,
+ label = n.body,
+ })
+
+ local actions = Widget.Box({
+ class_name = "actions",
+ map(n.actions, function(action)
+ return Widget.Button({
+ on_click_release = function()
+ return n:invoke(action.id)
+ end,
+ class_name = "action-button",
+ hexpand = true,
+ label = action.label,
+ })
+ end),
+ })
+ return Widget.EventBox({
+ Widget.Box({
+ class_name = "notification",
+ orientation = "VERTICAL",
+ Widget.Box({
+ icon,
+ Widget.Box({
+ orientation = "VERTICAL",
+ title,
+ body,
+ }),
+ }),
+ actions,
+ }),
+ })
+end
+
+return function(gdkmonitor)
+ local n_list = {}
+
+ local list = Widget.Box({
+ orientation = "VERTICAL",
+ setup = function(self)
+ self:hook(notifd, "notified", function(_, id)
+ local n = notifd:get_notification(id)
+ n_list[id] = Notification(n)
+ self:add(n_list[id])
+ local timeout_ms = n.expire_timeout > 0 and n.expire_timeout or NOTIFICATION_TIMEOUTMS
+ timeout(timeout_ms, function()
+ return n:dismiss()
+ end)
+ end)
+ self:hook(notifd, "resolved", function(_, id)
+ if n_list[id] then
+ n_list[id]:destroy()
+ n_list[id] = nil
+ end
+ end)
+ end,
+ })
+
+ return Widget.Window({
+ namespace = "notifications",
+ gdkmonitor = gdkmonitor,
+ anchor = astal.Astal.WindowAnchor.TOP,
+ layer = "OVERLAY",
+ class_name = "notification-popups",
+ visible = bind(list, "children"):as(function(v)
+ return v and #v > 0
+ end),
+ list,
+ })
+end