diff options
author | Aylur <[email protected]> | 2025-01-16 17:37:00 +0100 |
---|---|---|
committer | Aylur <[email protected]> | 2025-01-16 17:37:04 +0100 |
commit | 9e8634d892c559c5b44565a68bf35b13cbcb5572 (patch) | |
tree | 36a8b911e919959cdf64d3c64646f5066c6a2523 /examples/gtk3/lua/simple-bar | |
parent | bc796ac226800c43e724e27f53f410c157acaffe (diff) |
add: gtk3 ts popover example
closes #224
closes #157
Diffstat (limited to 'examples/gtk3/lua/simple-bar')
-rw-r--r-- | examples/gtk3/lua/simple-bar/README.md | 13 | ||||
-rw-r--r-- | examples/gtk3/lua/simple-bar/init.lua | 24 | ||||
-rw-r--r-- | examples/gtk3/lua/simple-bar/lib.lua | 25 | ||||
-rw-r--r-- | examples/gtk3/lua/simple-bar/style.scss | 106 | ||||
-rw-r--r-- | examples/gtk3/lua/simple-bar/widget/Bar.lua | 198 |
5 files changed, 366 insertions, 0 deletions
diff --git a/examples/gtk3/lua/simple-bar/README.md b/examples/gtk3/lua/simple-bar/README.md new file mode 100644 index 0000000..48cc27c --- /dev/null +++ b/examples/gtk3/lua/simple-bar/README.md @@ -0,0 +1,13 @@ +# Simple Bar Example + + + +A simple bar for Hyprland using + +- [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/gtk3/lua/simple-bar/init.lua b/examples/gtk3/lua/simple-bar/init.lua new file mode 100644 index 0000000..8c412fb --- /dev/null +++ b/examples/gtk3/lua/simple-bar/init.lua @@ -0,0 +1,24 @@ +local astal = require("astal") +local App = require("astal.gtk3.app") + +local Bar = require("widget.Bar") +local src = require("lib").src + +local scss = src("style.scss") +local css = "/tmp/style.css" + +astal.exec("sass " .. scss .. " " .. css) + +App:start({ + instance_name = "lua", + css = css, + request_handler = function(msg, res) + print(msg) + res("ok") + end, + main = function() + for _, mon in pairs(App.monitors) do + Bar(mon) + end + end, +}) diff --git a/examples/gtk3/lua/simple-bar/lib.lua b/examples/gtk3/lua/simple-bar/lib.lua new file mode 100644 index 0000000..d94db5c --- /dev/null +++ b/examples/gtk3/lua/simple-bar/lib.lua @@ -0,0 +1,25 @@ +local Variable = require("astal").Variable + +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 + +M.date = Variable(""):poll(1000, "date") + +return M diff --git a/examples/gtk3/lua/simple-bar/style.scss b/examples/gtk3/lua/simple-bar/style.scss new file mode 100644 index 0000000..f5f771a --- /dev/null +++ b/examples/gtk3/lua/simple-bar/style.scss @@ -0,0 +1,106 @@ +@use "sass:color"; + +$bg: #212223; +$fg: #f1f1f1; +$accent: #378DF7; +$radius: 7px; + +window.Bar { + border: none; + box-shadow: none; + background-color: $bg; + color: $fg; + font-size: 1.1em; + font-weight: bold; + + label { + margin: 0 8px; + } + + .Workspaces { + button { + all: unset; + background-color: transparent; + + &:hover label { + background-color: color.adjust($fg, $alpha: -0.84); + border-color: color.adjust($accent, $alpha: -0.8); + } + + &:active label { + background-color: color.adjust($fg, $alpha: -0.8) + } + } + + label { + transition: 200ms; + padding: 0 8px; + margin: 2px; + border-radius: $radius; + border: 1pt solid transparent; + } + + .focused label { + color: $accent; + border-color: $accent; + } + } + + .SysTray { + margin-right: 8px; + + button { + padding: 0 4px; + } + } + + .FocusedClient { + color: $accent; + } + + .Media .Cover { + min-height: 1.2em; + min-width: 1.2em; + border-radius: $radius; + background-position: center; + background-size: contain; + } + + .Battery label { + padding-left: 0; + margin-left: 0; + } + + .AudioSlider { + * { + all: unset; + } + + icon { + margin-right: .6em; + } + + & { + margin: 0 1em; + } + + trough { + background-color: color.adjust($fg, $alpha: -0.8); + border-radius: $radius; + } + + highlight { + background-color: $accent; + min-height: .8em; + border-radius: $radius; + } + + slider { + background-color: $fg; + border-radius: $radius; + min-height: 1em; + min-width: 1em; + margin: -.2em; + } + } +} diff --git a/examples/gtk3/lua/simple-bar/widget/Bar.lua b/examples/gtk3/lua/simple-bar/widget/Bar.lua new file mode 100644 index 0000000..155b9b8 --- /dev/null +++ b/examples/gtk3/lua/simple-bar/widget/Bar.lua @@ -0,0 +1,198 @@ +local astal = require("astal") +local Widget = require("astal.gtk3.widget") +local Variable = astal.Variable +local GLib = astal.require("GLib") +local bind = astal.bind +local Mpris = astal.require("AstalMpris") +local Battery = astal.require("AstalBattery") +local Wp = astal.require("AstalWp") +local Network = astal.require("AstalNetwork") +local Tray = astal.require("AstalTray") +local Hyprland = astal.require("AstalHyprland") +local map = require("lib").map + +local function SysTray() + local tray = Tray.get_default() + + return Widget.Box({ + class_name = "SysTray", + bind(tray, "items"):as(function(items) + return map(items, function(item) + return Widget.MenuButton({ + 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) + end), + }) +end + +local function FocusedClient() + local hypr = Hyprland.get_default() + local focused = bind(hypr, "focused-client") + + return Widget.Box({ + class_name = "Focused", + visible = focused, + focused:as(function(client) + return client and Widget.Label({ + label = bind(client, "title"):as(tostring), + }) + end), + }) +end + +local function Wifi() + local network = Network.get_default() + local wifi = bind(network, "wifi") + + return Widget.Box({ + visible = wifi:as(function(v) + return v ~= nil + end), + wifi:as(function(w) + return Widget.Icon({ + tooltip_text = bind(w, "ssid"):as(tostring), + class_name = "Wifi", + icon = bind(w, "icon-name"), + }) + end), + }) +end + +local function AudioSlider() + local speaker = Wp.get_default().audio.default_speaker + + return Widget.Box({ + class_name = "AudioSlider", + css = "min-width: 140px;", + Widget.Icon({ + icon = bind(speaker, "volume-icon"), + }), + Widget.Slider({ + hexpand = true, + on_dragged = function(self) + speaker.volume = self.value + end, + value = bind(speaker, "volume"), + }), + }) +end + +local function BatteryLevel() + 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 + +local function Media() + local player = Mpris.Player.new("spotify") + + return Widget.Box({ + class_name = "Media", + visible = bind(player, "available"), + Widget.Box({ + class_name = "Cover", + valign = "CENTER", + css = bind(player, "cover-art"):as(function(cover) + return "background-image: url('" .. (cover or "") .. "');" + end), + }), + Widget.Label({ + label = bind(player, "metadata"):as(function() + return (player.title or "") .. " - " .. (player.artist or "") + end), + }), + }) +end + +local function Workspaces() + local hypr = Hyprland.get_default() + + return Widget.Box({ + class_name = "Workspaces", + bind(hypr, "workspaces"):as(function(wss) + table.sort(wss, function(a, b) + return a.id < b.id + end) + + return map(wss, function(ws) + if not (ws.id >= -99 and ws.id <= -2) then -- filter out special workspaces + return Widget.Button({ + class_name = bind(hypr, "focused-workspace"):as(function(fw) + return fw == ws and "focused" or "" + end), + on_clicked = function() + ws:focus() + end, + label = bind(ws, "id"):as(function(v) + return type(v) == "number" and string.format("%.0f", v) or v + end), + }) + end + end) + end), + }) +end + +local function Time(format) + local time = Variable(""):poll(1000, function() + return GLib.DateTime.new_now_local():format(format) + end) + + return Widget.Label({ + class_name = "Time", + on_destroy = function() + time:drop() + end, + label = time(), + }) +end + +return function(gdkmonitor) + local WindowAnchor = astal.require("Astal", "3.0").WindowAnchor + + return Widget.Window({ + class_name = "Bar", + gdkmonitor = gdkmonitor, + anchor = WindowAnchor.TOP + WindowAnchor.LEFT + WindowAnchor.RIGHT, + exclusivity = "EXCLUSIVE", + + Widget.CenterBox({ + Widget.Box({ + halign = "START", + Workspaces(), + FocusedClient(), + }), + Widget.Box({ + Media(), + }), + Widget.Box({ + halign = "END", + SysTray(), + Wifi(), + AudioSlider(), + BatteryLevel(), + Time("%H:%M - %A %e."), + }), + }), + }) +end |