diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/lua/notification-popups/README.md | 14 | ||||
-rw-r--r-- | examples/lua/notification-popups/init.lua | 21 | ||||
-rw-r--r-- | examples/lua/notification-popups/lib.lua | 52 | ||||
-rw-r--r-- | examples/lua/notification-popups/style.scss | 69 | ||||
-rw-r--r-- | examples/lua/notification-popups/widget/notifications.lua | 125 |
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 + + + +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 |