From 10136ab9de37a27d3360c23cc98653c7c1cdf407 Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Thu, 24 Apr 2025 16:58:30 +0200 Subject: [PATCH] [AGS] Bar: Done (WiFi still missing, will be added at some later point) --- config/astal/app.ts | 16 +- config/astal/btconf | 1 + .../components/QuickActions/QuickActions.tsx | 74 ++++++ config/astal/components/QuickActions/dump | 35 +++ .../QuickActions/modules/Audio/Audio.scss | 3 + .../QuickActions/modules/Audio/Audio.tsx | 16 +- .../QuickActions/modules/Battery.tsx | 52 +++++ .../modules/Bluetooth/Bluetooth.tsx | 68 ++++-- .../QuickActions/modules/Bluetooth/Device.tsx | 32 ++- .../modules/Brightness/Brightness.tsx | 18 ++ .../modules/Networking-old/Networking.tsx | 0 .../modules/Networking-old/README.md | 0 .../modules/Networking-old/network.d.ts | 0 .../Networking-old/networkinghelper.ts | 0 .../modules/Networking/Network.tsx | 97 ++++++++ .../modules/Networking/NetworkMenu.tsx | 18 ++ .../modules/Networking/dump} | 0 .../modules/Networking/network-helper.ts | 0 .../modules/Networking/network.d.ts | 0 .../modules/Networking/wifi-helper.ts | 0 .../QuickActions/modules/Player/Player.scss | 56 +++++ .../QuickActions/modules/Player/Player.tsx | 154 +++++++++++++ .../ui => }/QuickActions/modules/Power.tsx | 56 +++-- .../components/QuickActions/quickactions.scss | 56 +++++ config/astal/components/bar/{ui => }/Bar.tsx | 1 - config/astal/components/bar/bar.scss | 62 +++++ .../astal/components/bar/modules/Calendar.tsx | 26 +++ .../astal/components/bar/modules/Hyprland.tsx | 197 ++++++++++++++++ .../components/bar/modules/QuickView.tsx | 186 +++++++++++++++ .../components/bar/modules/SystemInfo.tsx | 211 ++++++++++++++++++ .../bar/{ui => }/modules/stats.d.ts | 0 .../bar/ui/QuickActions/QuickActions.tsx | 28 --- .../modules/Bluetooth/bthelper.ts | 0 .../modules/Brightness/Brightness.tsx | 0 .../ui/QuickActions/modules/Player/Player.tsx | 0 .../bar/ui/QuickActions/quickactions.scss | 13 -- config/astal/components/bar/ui/bar.scss | 19 -- .../components/bar/ui/modules/Calendar.tsx | 23 -- .../components/bar/ui/modules/Hyprland.tsx | 157 ------------- .../components/bar/ui/modules/QuickView.tsx | 117 ---------- .../components/bar/ui/modules/SystemInfo.tsx | 135 ----------- config/astal/components/bar/util/sysinfo.ts | 0 config/astal/no-avatar-icon.jpg | Bin 0 -> 8853 bytes config/astal/style.scss | 17 +- .../{components/bar => }/util/brightness.ts | 0 config/astal/util/colours.scss | 4 + config/astal/util/state.ts | 3 + scripts/get-profile-picture | 20 ++ 48 files changed, 1423 insertions(+), 548 deletions(-) create mode 100644 config/astal/btconf create mode 100644 config/astal/components/QuickActions/QuickActions.tsx create mode 100644 config/astal/components/QuickActions/dump create mode 100644 config/astal/components/QuickActions/modules/Audio/Audio.scss rename config/astal/components/{bar/ui => }/QuickActions/modules/Audio/Audio.tsx (93%) create mode 100644 config/astal/components/QuickActions/modules/Battery.tsx rename config/astal/components/{bar/ui => }/QuickActions/modules/Bluetooth/Bluetooth.tsx (66%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Bluetooth/Device.tsx (52%) create mode 100644 config/astal/components/QuickActions/modules/Brightness/Brightness.tsx rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking-old/Networking.tsx (100%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking-old/README.md (100%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking-old/network.d.ts (100%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking-old/networkinghelper.ts (100%) create mode 100644 config/astal/components/QuickActions/modules/Networking/Network.tsx create mode 100644 config/astal/components/QuickActions/modules/Networking/NetworkMenu.tsx rename config/astal/components/{bar/ui/QuickActions/modules/Networking/Network.tsx => QuickActions/modules/Networking/dump} (100%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking/network-helper.ts (100%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking/network.d.ts (100%) rename config/astal/components/{bar/ui => }/QuickActions/modules/Networking/wifi-helper.ts (100%) create mode 100644 config/astal/components/QuickActions/modules/Player/Player.scss create mode 100644 config/astal/components/QuickActions/modules/Player/Player.tsx rename config/astal/components/{bar/ui => }/QuickActions/modules/Power.tsx (66%) create mode 100644 config/astal/components/QuickActions/quickactions.scss rename config/astal/components/bar/{ui => }/Bar.tsx (97%) create mode 100644 config/astal/components/bar/bar.scss create mode 100644 config/astal/components/bar/modules/Calendar.tsx create mode 100644 config/astal/components/bar/modules/Hyprland.tsx create mode 100644 config/astal/components/bar/modules/QuickView.tsx create mode 100644 config/astal/components/bar/modules/SystemInfo.tsx rename config/astal/components/bar/{ui => }/modules/stats.d.ts (100%) delete mode 100644 config/astal/components/bar/ui/QuickActions/QuickActions.tsx delete mode 100644 config/astal/components/bar/ui/QuickActions/modules/Bluetooth/bthelper.ts delete mode 100644 config/astal/components/bar/ui/QuickActions/modules/Brightness/Brightness.tsx delete mode 100644 config/astal/components/bar/ui/QuickActions/modules/Player/Player.tsx delete mode 100644 config/astal/components/bar/ui/QuickActions/quickactions.scss delete mode 100644 config/astal/components/bar/ui/bar.scss delete mode 100644 config/astal/components/bar/ui/modules/Calendar.tsx delete mode 100644 config/astal/components/bar/ui/modules/Hyprland.tsx delete mode 100644 config/astal/components/bar/ui/modules/QuickView.tsx delete mode 100644 config/astal/components/bar/ui/modules/SystemInfo.tsx delete mode 100644 config/astal/components/bar/util/sysinfo.ts create mode 100644 config/astal/no-avatar-icon.jpg rename config/astal/{components/bar => }/util/brightness.ts (100%) create mode 100644 config/astal/util/colours.scss create mode 100644 config/astal/util/state.ts create mode 100755 scripts/get-profile-picture diff --git a/config/astal/app.ts b/config/astal/app.ts index 6a02a3f..856547e 100644 --- a/config/astal/app.ts +++ b/config/astal/app.ts @@ -1,21 +1,23 @@ import { App } from "astal/gtk4" import style from "./style.scss" - -// import notifications from "./components/notifications/handler"; -import Bar from "./components/bar/ui/Bar"; +import Bar from "./components/bar/Bar"; +import AstalHyprland from "gi://AstalHyprland?version=0.1"; App.start({ instanceName: "runner", css: style, main() { - // notifications.startNotificationHandler( App.get_monitors()[0] ); - // TODO: Monitor handling - Bar.Bar( App.get_monitors()[0] ); + const hypr = AstalHyprland.get_default(); + const monitors = App.get_monitors(); + for (let index = 0; index < monitors.length; index++) { + Bar.Bar( monitors[ index ] ); + } + + // TODO: Handle monitor add }, requestHandler(request, res) { const args = request.trimStart().split( ' ' ); - // Notifications (TODO: Handle the arguments in the components themselves) if ( args[ 0 ] === 'notifier' ) { res( 'Not available here yet, run astal -i notifier ' + args[ 1 ] ); // res( notifications.cliHandler( args ) ); diff --git a/config/astal/btconf b/config/astal/btconf new file mode 100644 index 0000000..02e4a84 --- /dev/null +++ b/config/astal/btconf @@ -0,0 +1 @@ +false \ No newline at end of file diff --git a/config/astal/components/QuickActions/QuickActions.tsx b/config/astal/components/QuickActions/QuickActions.tsx new file mode 100644 index 0000000..dd97f62 --- /dev/null +++ b/config/astal/components/QuickActions/QuickActions.tsx @@ -0,0 +1,74 @@ +import { Gtk } from "astal/gtk4"; +import Power from "./modules/Power"; +import Audio from "./modules/Audio/Audio"; +import Bluetooth from "./modules/Bluetooth/Bluetooth"; +import Brightness from "./modules/Brightness/Brightness"; +import Player from "./modules/Player/Player"; +import { BatteryBox } from "./modules/Battery"; +import { exec } from "astal"; +import Network from "./modules/Networking/Network"; + +const QuickActions = () => { + const popover = new Gtk.Popover({ cssClasses: ["quick-actions-wrapper"] }); + popover.set_child(renderQuickActions()); + return popover; +}; + +const renderQuickActions = () => { + const user = exec("/bin/sh -c whoami"); + const profile = exec("/bin/fish -c get-profile-picture"); + const cwd = exec("pwd"); + const um = Power.UserMenu(); + + return ( + + um.popup()} + cssClasses={["stealthy-button"]} + child={ + + {um} + + } + > + + + } + > + } + endWidget={ + + + + + } + > + + + + + + + + + + + ); +}; + +// TODO: Expose additional functions to be usable through CLI +export default { + QuickActions, +}; diff --git a/config/astal/components/QuickActions/dump b/config/astal/components/QuickActions/dump new file mode 100644 index 0000000..6305c6f --- /dev/null +++ b/config/astal/components/QuickActions/dump @@ -0,0 +1,35 @@ +import { Gtk } from "astal/gtk4"; +import Power from "./modules/Power"; +import Audio from "./modules/Audio/Audio"; +import Bluetooth from "./modules/Bluetooth/Bluetooth"; +import Brightness from "./modules/Brightness/Brightness"; +import Player from "./modules/Player/Player"; +import { BatteryBox } from "./modules/Battery"; + +const QuickActions = () => { + const popover = new Gtk.Overlay( { cssClasses: [ 'quick-actions-wrapper' ] } ); + popover.set_child(renderQuickActions()); + return popover; +}; + +const renderQuickActions = () => { + return ( + + + + + + + + + + + + + ); +}; + +// TODO: Expose additional functions to be usable through CLI +export default { + QuickActions, +}; diff --git a/config/astal/components/QuickActions/modules/Audio/Audio.scss b/config/astal/components/QuickActions/modules/Audio/Audio.scss new file mode 100644 index 0000000..2d35eb1 --- /dev/null +++ b/config/astal/components/QuickActions/modules/Audio/Audio.scss @@ -0,0 +1,3 @@ +.audio-box { + min-width: 320px; +} diff --git a/config/astal/components/bar/ui/QuickActions/modules/Audio/Audio.tsx b/config/astal/components/QuickActions/modules/Audio/Audio.tsx similarity index 93% rename from config/astal/components/bar/ui/QuickActions/modules/Audio/Audio.tsx rename to config/astal/components/QuickActions/modules/Audio/Audio.tsx index de5a95f..3f2d4b4 100644 --- a/config/astal/components/bar/ui/QuickActions/modules/Audio/Audio.tsx +++ b/config/astal/components/QuickActions/modules/Audio/Audio.tsx @@ -18,13 +18,14 @@ const AudioModule = () => { return ( - + @@ -42,11 +43,13 @@ const AudioModule = () => { max={100} min={0} step={1} - widthRequest={100} + hexpand + vexpand onChangeValue={self => setVolumeSpeaker(self.value)} > - + @@ -70,15 +74,44 @@ const openBTPicker = () => { }; const BluetoothPickerList = () => { + let btEnableState = readFile("./btconf") === "true" ? true : false; + bt.adapter.set_powered(btEnableState); + + const updateState = () => { + btEnableState = !btEnableState; + writeFile("./btconf", "" + btEnableState); + }; + return ( - bt.adapter.stop_discovery()}> - + bt.adapter.stop_discovery()} + cssClasses={["popover-box"]} + > + - + } + endWidget={ + updateState()} + > + } + > + + + {bind(bt, "devices").as(devices => { return devices .filter(device => { - if (device.get_connected()) { + if (device.get_connected() || device.get_paired()) { return device; } }) @@ -91,13 +124,13 @@ const BluetoothPickerList = () => { visible={bind(bt, "devices").as(devices => { return ( devices.filter(device => { - if (device.get_connected()) { + if (device.get_connected() || device.get_paired()) { return device; } }).length === 0 ); })} - label={"No connected devices"} + label={"No connected / trusted devices"} cssClasses={["bt-no-found", "bt-conn-list"]} > } > } onClicked={() => { - // TODO: Make sure to check if device was previously paired and otherwise do some pairing shenanigans - device.connect_device( () => {} ); + connectOrPair( device ); }} > ); }; +const connectOrPair = (device: AstalBluetooth.Device) => { + if ( device.get_paired() ) { + device.connect_device(() => { }); + // Show failed message if tried to connect and failed + } else { + device.pair(); + } +}; export default BTDevice; diff --git a/config/astal/components/QuickActions/modules/Brightness/Brightness.tsx b/config/astal/components/QuickActions/modules/Brightness/Brightness.tsx new file mode 100644 index 0000000..5ddaa36 --- /dev/null +++ b/config/astal/components/QuickActions/modules/Brightness/Brightness.tsx @@ -0,0 +1,18 @@ +import { bind } from "astal"; +import Brightness from "../../../../util/brightness"; + +const brightness = Brightness.get_default(); + +const BrightnessModule = () => { + return ( + + + + + + ); +}; + +export default { + BrightnessModule +}; diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking-old/Networking.tsx b/config/astal/components/QuickActions/modules/Networking-old/Networking.tsx similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking-old/Networking.tsx rename to config/astal/components/QuickActions/modules/Networking-old/Networking.tsx diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking-old/README.md b/config/astal/components/QuickActions/modules/Networking-old/README.md similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking-old/README.md rename to config/astal/components/QuickActions/modules/Networking-old/README.md diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking-old/network.d.ts b/config/astal/components/QuickActions/modules/Networking-old/network.d.ts similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking-old/network.d.ts rename to config/astal/components/QuickActions/modules/Networking-old/network.d.ts diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking-old/networkinghelper.ts b/config/astal/components/QuickActions/modules/Networking-old/networkinghelper.ts similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking-old/networkinghelper.ts rename to config/astal/components/QuickActions/modules/Networking-old/networkinghelper.ts diff --git a/config/astal/components/QuickActions/modules/Networking/Network.tsx b/config/astal/components/QuickActions/modules/Networking/Network.tsx new file mode 100644 index 0000000..fe16d05 --- /dev/null +++ b/config/astal/components/QuickActions/modules/Networking/Network.tsx @@ -0,0 +1,97 @@ +import { bind } from "astal"; +import { Gtk } from "astal/gtk4"; +import AstalNetwork from "gi://AstalNetwork"; +import networkHelper from "./network-helper"; +import NetworkMenu from "./NetworkMenu"; + +const net = AstalNetwork.get_default(); +const STATE = AstalNetwork.DeviceState; + +const Network = () => { + const netMenu = NetworkMenu.NetworkMenu(); + return ( + + + + + ); +}; + +export default { + Network, +}; diff --git a/config/astal/components/QuickActions/modules/Networking/NetworkMenu.tsx b/config/astal/components/QuickActions/modules/Networking/NetworkMenu.tsx new file mode 100644 index 0000000..6a02e31 --- /dev/null +++ b/config/astal/components/QuickActions/modules/Networking/NetworkMenu.tsx @@ -0,0 +1,18 @@ +import { Gtk } from "astal/gtk4"; + +const NetworkMenu = () => { + const popover = new Gtk.Popover(); + popover.set_child( renderMenu() ); + return popover; +}; + +const renderMenu = () => { + return + + + ; +}; + +export default { + NetworkMenu, +}; diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking/Network.tsx b/config/astal/components/QuickActions/modules/Networking/dump similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking/Network.tsx rename to config/astal/components/QuickActions/modules/Networking/dump diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking/network-helper.ts b/config/astal/components/QuickActions/modules/Networking/network-helper.ts similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking/network-helper.ts rename to config/astal/components/QuickActions/modules/Networking/network-helper.ts diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking/network.d.ts b/config/astal/components/QuickActions/modules/Networking/network.d.ts similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking/network.d.ts rename to config/astal/components/QuickActions/modules/Networking/network.d.ts diff --git a/config/astal/components/bar/ui/QuickActions/modules/Networking/wifi-helper.ts b/config/astal/components/QuickActions/modules/Networking/wifi-helper.ts similarity index 100% rename from config/astal/components/bar/ui/QuickActions/modules/Networking/wifi-helper.ts rename to config/astal/components/QuickActions/modules/Networking/wifi-helper.ts diff --git a/config/astal/components/QuickActions/modules/Player/Player.scss b/config/astal/components/QuickActions/modules/Player/Player.scss new file mode 100644 index 0000000..a26faac --- /dev/null +++ b/config/astal/components/QuickActions/modules/Player/Player.scss @@ -0,0 +1,56 @@ +$fg-color: #{"@theme_fg_color"}; +$bg-color: #{"@theme_bg_color"}; + +box.players-box { + margin-top: 20px; +} + +box.player { + padding: 0.6rem; + + .cover-art { + min-width: 100px; + min-height: 100px; + border-radius: 9px; + margin-right: 0.6rem; + background-size: contain; + background-position: center; + } + + .title { + font-weight: bold; + font-size: 1.1em; + } + + scale { + padding: 0; + margin: 0.4rem 0; + border-radius: 20px; + + trough { + min-height: 8px; + border-radius: 20px; + } + + highlight { + background-color: $fg-color; + border-radius: 20px; + } + + slider { + all: unset; + border-radius: 20px; + } + } + + centerbox.actions { + min-width: 220px; + + button { + min-width: 0; + min-height: 0; + padding: 0.4rem; + margin: 0 0.2rem; + } + } +} diff --git a/config/astal/components/QuickActions/modules/Player/Player.tsx b/config/astal/components/QuickActions/modules/Player/Player.tsx new file mode 100644 index 0000000..7e3516b --- /dev/null +++ b/config/astal/components/QuickActions/modules/Player/Player.tsx @@ -0,0 +1,154 @@ +import { bind } from "astal"; +import { Gtk } from "astal/gtk4"; +import AstalMpris from "gi://AstalMpris"; +import Pango from "gi://Pango?version=1.0"; +const ALIGN = Gtk.Align; + +const mpris = AstalMpris.get_default(); +mpris.connect("player-added", p => { + print("Player added:", p); +}); + +const PlayerModule = () => { + return ( + + + + + {bind(mpris, "players").as(players => { + return players.map(player => { + return ; + }); + })} + + + + ); +}; + +// TODO: Update widths +const pbStatus = AstalMpris.PlaybackStatus; +const PlayerItem = ({ player }: { player: AstalMpris.Player }) => { + return ( + + + + + + l > 0)} + value={bind(player, "position")} + min={0} + max={bind(player, "length")} + onChangeValue={v => + player.set_position(v.get_value()) + } + > + + secondsToFriendlyTime(v), + )} + hexpand + cssClasses={["position"]} + > + } + centerWidget={ + + + + + + } + endWidget={ + + } + > + + + ); +}; + +const secondsToFriendlyTime = (time: number) => { + const minutes = Math.floor(time / 60); + const hours = Math.floor(minutes / 60); + const seconds = Math.floor(time % 60); + if (hours > 0) { + return `${hours}:${expandTime(minutes)}:${expandTime(seconds)}`; + } else { + return `${minutes}:${expandTime(seconds)}`; + } +}; + +const expandTime = (time: number): string => { + return time < 10 ? `0${time}` : "" + time; +}; + +export default { + PlayerModule, +}; diff --git a/config/astal/components/bar/ui/QuickActions/modules/Power.tsx b/config/astal/components/QuickActions/modules/Power.tsx similarity index 66% rename from config/astal/components/bar/ui/QuickActions/modules/Power.tsx rename to config/astal/components/QuickActions/modules/Power.tsx index 36442c0..5402073 100644 --- a/config/astal/components/bar/ui/QuickActions/modules/Power.tsx +++ b/config/astal/components/QuickActions/modules/Power.tsx @@ -12,29 +12,17 @@ const PowerMenu = (): Gtk.Popover => { child={ } - onClicked={() => exec("shutdown now")} + onClicked={() => exec("/bin/sh -c 'shutdown now'")} > - - ); @@ -48,7 +36,10 @@ const Power = () => { const pm = PowerMenu(); return ( + + + ); + }; + + popover.set_child(powerMenuBox()); + return popover; +}; + +export default { + Power, + UserMenu +}; diff --git a/config/astal/components/QuickActions/quickactions.scss b/config/astal/components/QuickActions/quickactions.scss new file mode 100644 index 0000000..8f0302d --- /dev/null +++ b/config/astal/components/QuickActions/quickactions.scss @@ -0,0 +1,56 @@ +@use "./modules/Player/Player.scss"; +@use "./modules/Audio/Audio.scss"; +@use "../../util/colours.scss" as *; + +.quick-actions-wrapper { + min-width: 520px; +} + +box.quick-actions { + padding: 10px; +} + +popover * { + border-radius: 20px; +} + +button { + margin: 4px; +} + +.button-no-margin { + margin-top: 0; + margin-bottom: 0; +} + +.devices-list { + margin-bottom: 20px; +} + +button.toggle-button { + min-width: 220px; + border-radius: 50px; + + &.toggle-on { + min-width: 190px; + margin-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + background-color: $accent-color; + } +} + +button.actions-button { + margin-left: 0; + border-radius: 0; + background-color: $accent-color; + border-top-right-radius: 50px; + border-bottom-right-radius: 50px; +} + +.avatar-icon { + border-radius: 100px; + min-height: 40px; + min-width: 40px; + margin-right: 10px; +} diff --git a/config/astal/components/bar/ui/Bar.tsx b/config/astal/components/bar/Bar.tsx similarity index 97% rename from config/astal/components/bar/ui/Bar.tsx rename to config/astal/components/bar/Bar.tsx index 1f38694..3a1c273 100644 --- a/config/astal/components/bar/ui/Bar.tsx +++ b/config/astal/components/bar/Bar.tsx @@ -23,7 +23,6 @@ const Bar = (gdkmonitor: Gdk.Monitor) => { diff --git a/config/astal/components/bar/bar.scss b/config/astal/components/bar/bar.scss new file mode 100644 index 0000000..156653d --- /dev/null +++ b/config/astal/components/bar/bar.scss @@ -0,0 +1,62 @@ +@use "../../util/colours.scss" as *; + +window.Bar { + font-family: "Comfortaa, sans-serif"; + background: transparent; + color: $fg-color; + font-weight: bold; + + /* >centerbox { */ + /* background: $bg-color; */ + /* border-radius: 10px; */ + /* margin: 8px; */ + /* } */ + + .bar-button { + border-radius: 20px; + margin: 2px; + padding-left: 10px; + padding-right: 10px; + background-color: $bg-color; + + & button { + background-color: $bg-color; + } + } + + .quick-action-button { + border-radius: 20px; + margin: 2px; + padding-left: 10px; + padding-right: 10px; + background-color: $bg-color; + } + + button.workspace-button { + border-radius: 20px; + margin: 1px; + + &.focused-workspace-button { + color: $accent-color-2; + } + } + + .tray-item { + margin: 0; + padding: 0; + + & button { + margin: 2px; + box-shadow: none; + } + } + + .time { + min-width: 11rem; + padding: 3px; + & button { + box-shadow: none; + padding: 0; + } + } +} diff --git a/config/astal/components/bar/modules/Calendar.tsx b/config/astal/components/bar/modules/Calendar.tsx new file mode 100644 index 0000000..db6d06b --- /dev/null +++ b/config/astal/components/bar/modules/Calendar.tsx @@ -0,0 +1,26 @@ +import { GLib, Variable } from "astal"; +import { Gtk } from "astal/gtk4"; + +const Time = ({ format = "%a, %e.%m %H:%M:%S" }) => { + const time = Variable("").poll( + 1000, + () => GLib.DateTime.new_now_local().format(format)!, + ); + + return ( + + + + + + + ); +}; + +export default { + Time, +}; diff --git a/config/astal/components/bar/modules/Hyprland.tsx b/config/astal/components/bar/modules/Hyprland.tsx new file mode 100644 index 0000000..d540b5e --- /dev/null +++ b/config/astal/components/bar/modules/Hyprland.tsx @@ -0,0 +1,197 @@ +import AstalTray from "gi://AstalTray"; +import { bind, GObject } from "astal"; +import AstalHyprland from "gi://AstalHyprland"; +import { Gtk } from "astal/gtk4"; + +const SYNC = GObject.BindingFlags.SYNC_CREATE; + +const SysTray = () => { + const trayBox = new Gtk.Box({ cssClasses: ["bar-button"] }); + const tray = AstalTray.get_default(); + + const trayItems = new Map(); + const trayAddedHandler = tray.connect("item-added", (_, id) => { + const item = tray.get_item(id); + const popover = Gtk.PopoverMenu.new_from_model(item.menu_model); + const icon = new Gtk.Image(); + const button = new Gtk.MenuButton({ + popover, + child: icon, + cssClasses: ["tray-item"], + }); + + item.bind_property("gicon", icon, "gicon", SYNC); + popover.insert_action_group("dbusmenu", item.action_group); + item.connect("notify::action-group", () => { + popover.insert_action_group("dbusmenu", item.action_group); + }); + + trayItems.set(id, button); + trayBox.append(button); + }); + + const trayRemovedHandler = tray.connect("item-removed", (_, id) => { + const button = trayItems.get(id); + if (button) { + trayBox.remove(button); + button.run_dispose(); + trayItems.delete(id); + } + }); + + trayBox.connect("destroy", () => { + tray.disconnect(trayAddedHandler); + tray.disconnect(trayRemovedHandler); + }); + + return trayBox; +}; + +const Workspace = () => { + const hypr = AstalHyprland.get_default(); + + return ( + + {bind(hypr, "workspaces").as(wss => + wss + .filter(ws => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces + .sort((a, b) => a.id - b.id) + .map(ws => ( + + )), + )} + + ); +}; + +/** + * Displays the name of the currently active window and provides a popover for + * displaying all available clients + */ +const ActiveWindow = () => { + const hypr = AstalHyprland.get_default(); + const focused = bind(hypr, "focusedClient"); + + const WindowPopover = (): Gtk.Popover => { + // Set up boxes + Popover + const clients = new Map(); + const popover = new Gtk.Popover(); + const popoverBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + }); + + const widgetTitle = new Gtk.Label({ + cssClasses: ["title-2"], + label: "Available Windows", + }); + + popoverBox.append(widgetTitle); + + const seaparator = new Gtk.Separator({ + marginTop: 5, + marginBottom: 10, + }); + + popoverBox.append(seaparator); + + const addClient = (client: AstalHyprland.Client) => { + const clientBox = new Gtk.Box(); + + // Workspace description + const descWS = new Gtk.Label({ label: "(WS " }); + + // Workpsace information + const workspace = new Gtk.Label(); + client.workspace.bind_property("name", workspace, "label", SYNC); + + const windowClassDesc = new Gtk.Label({ label: ") [" }); + + const windowClass = new Gtk.Label(); + windowClass.label = client.get_initial_class(); + + const titleDesc = new Gtk.Label({ label: "] " }); + titleDesc.set_margin_end(2); + + const title = new Gtk.Label(); + client.bind_property("title", title, "label", SYNC); + + clientBox.append(descWS); + clientBox.append(workspace); + clientBox.append(windowClassDesc); + clientBox.append(windowClass); + clientBox.append(titleDesc); + clientBox.append(title); + + const button = new Gtk.Button(); + button.connect( 'clicked', () => { + client.workspace.focus(); + } ); + button.set_child(clientBox); + + popoverBox.append(button); + + clients.set(client.get_address(), button); + }; + + // Populate with already added clients + const c = hypr.get_clients(); + for (let index = 0; index < c.length; index++) { + addClient(c[index]); + } + + hypr.connect("client-added", (_, client) => { + addClient(client); + }); + + hypr.connect("client-removed", (_, client) => { + const c = clients.get(client); + if (c) { + popoverBox.remove(c); + c.run_dispose(); + clients.delete(client); + } + }); + + popover.set_child(popoverBox); + return popover; + }; + + const windowPopover = WindowPopover(); + + // ─────────────────────────────────────────────────────────────────── + // Return fully assembled HyprlandFocusedClient box + // ─────────────────────────────────────────────────────────────────── + return ( + + + {windowPopover} + + ); +}; + +export default { + Workspace, + ActiveWindow, + SysTray, +}; diff --git a/config/astal/components/bar/modules/QuickView.tsx b/config/astal/components/bar/modules/QuickView.tsx new file mode 100644 index 0000000..f8c8177 --- /dev/null +++ b/config/astal/components/bar/modules/QuickView.tsx @@ -0,0 +1,186 @@ +import { bind } from "astal"; +import AstalBattery from "gi://AstalBattery"; +import AstalBluetooth from "gi://AstalBluetooth"; +import AstalNetwork from "gi://AstalNetwork"; +import AstalWp from "gi://AstalWp"; +import { Gtk } from "astal/gtk4"; +import Brightness from "../../../util/brightness"; +import QuickActions from "../../QuickActions/QuickActions"; + +const STATE = AstalNetwork.DeviceState; + +const QuickView = () => { + const qa = QuickActions.QuickActions(); + const showQuickActions = () => { + qa.popup(); + }; + + return ( + + ); +}; + +const NetworkWidget = () => { + const network = AstalNetwork.get_default(); + + return ( + + { + if (state === AstalNetwork.State.CONNECTING) { + return "chronometer-reset-symbolic"; + } else if ( + state === AstalNetwork.State.CONNECTED_LOCAL || + state === AstalNetwork.State.CONNECTED_SITE || + state === AstalNetwork.State.CONNECTED_GLOBAL + ) { + return "network-wired-activated-symbolic"; + } else { + return "paint-unknown-symbolic"; + } + })} + cssClasses={["network-widget", "quick-view-symbol"]} + visible={bind(network.wifi, "state").as( + state => state !== STATE.ACTIVATED, + )} + > + { + if (state === STATE.ACTIVATED) { + return network.wifi.iconName; + } else { + return ""; + } + })} + cssClasses={["network-widget", "quick-view-symbol"]} + visible={bind(network.wifi, "state").as( + state => state === STATE.ACTIVATED, + )} + > + + ); +}; + +const BluetoothWidget = () => { + const bluetooth = AstalBluetooth.get_default(); + const enabled = bind(bluetooth.adapter, "powered"); + const connected = bind(bluetooth, "isConnected"); + + // For each connected BT device, render status + return ( + + e)}> + c)} + > + !c)} + > + + !e)} + > + + {bind(bluetooth, "devices").as(devices => { + return devices.map(device => { + return ( + c)}> + icon, + )} + > + + + ); + }); + })} + + + ); +}; + +const BatteryWidget = () => { + const battery = AstalBattery.get_default(); + if (battery.get_is_present()) { + return ( + icon)} + cssClasses={["quick-view-symbol"]} + > + ); + } else { + return ; + } + // Else, no battery available -> Don't show the widget +}; + +const BrightnessWidget = () => { + const brightness = Brightness.get_default(); + const screen_brightness = bind(brightness, "screen"); + + return ( + + ); +}; + +const Audio = () => { + const wireplumber = AstalWp.get_default(); + if (wireplumber) { + return ( + + icon, + )} + cssClasses={["quick-view-symbol"]} + > + icon)} + cssClasses={["quick-view-symbol"]} + > + + ); + } else { + print( + "[ WirePlumber ] Could not connect, Audio support in bar will be missing", + ); + return ; + } +}; + +// cssClasses={[ 'quick-view-symbol' ]} + +export default { + QuickView, +}; diff --git a/config/astal/components/bar/modules/SystemInfo.tsx b/config/astal/components/bar/modules/SystemInfo.tsx new file mode 100644 index 0000000..f63c1f6 --- /dev/null +++ b/config/astal/components/bar/modules/SystemInfo.tsx @@ -0,0 +1,211 @@ +import { exec, execAsync, GLib, interval, Variable } from "astal"; +import { Gtk } from "astal/gtk4"; +import AstalBattery from "gi://AstalBattery?version=0.1"; + +const FETCH_INTERVAL = 2000; + +const cpuUtil = Variable("0%"); +const ramUtil = Variable("0%"); +const ramUsed = Variable("0MiB"); +const gpuUtil = Variable("0%"); +let gpuName = "card1"; +let enabled = false; + +const refreshStats = (): Stats => { + gpuName = exec(`/bin/bash -c "ls /sys/class/drm/ | grep '^card[0-9]*$'"`); + const cpuNameInSensors = "CPUTIN"; + const stats = { + kernel: exec("uname -sr"), + netSpeed: exec( + `/bin/bash -c "interface=$(ip route get 8.8.8.8 | awk '{print $5; exit}') && cat \"/sys/class/net/$interface/speed\""`, + ), + cpuTemp: exec( + `/bin/bash -c "sensors | grep -m1 ${cpuNameInSensors} | awk '{print $2}'"`, + ), + cpuClk: exec( + `awk '/cpu MHz/ {sum+=$4; ++n} END {print sum/n " MHz"}' /proc/cpuinfo`, + ), + gpuTemp: exec( + `/bin/bash -c "sensors | grep -E 'edge' | awk '{print $2}'"`, + ), + gpuClk: exec( + `/bin/bash -c "cat /sys/class/drm/${gpuName}/device/pp_dpm_sclk | grep '\\*' | awk '{print $2 $3}'"`, + ), + vram: + Math.round( + parseInt( + exec( + `cat /sys/class/drm/${gpuName}/device/mem_info_vram_used`, + ), + ) / + 1024 / + 1024, + ) + "MiB", + availableVRAM: + Math.round( + parseInt( + exec( + `cat /sys/class/drm/${gpuName}/device/mem_info_vram_total`, + ), + ) / + 1024 / + 1024, + ) + "MiB", + }; + + return stats; +}; + +const systemStats: Variable = Variable(refreshStats()); + +const availableFeatures = { + cpu: true, + ram: true, +}; + +const featureTest = () => { + // Check if awk & sed are available + try { + exec("awk -V"); + exec("sed --version"); + enabled = true; + } catch (e) { + printerr( + "[ SysInfo ] AWK or SED missing! No system info will be available", + ); + enabled = false; + return; + } + + // Check if mpstat is available + try { + exec("mpstat -V"); + } catch (e) { + availableFeatures.cpu = false; + printerr( + "[ SysInfo ] Feature Test for CPU info failed. mpstat from the sysstat package missing!", + ); + } +}; + +const info = () => { + return ( + + + + + + + + + ); +}; + +const SystemInformationPanel = () => { + const popover = new Gtk.Popover(); + + popover.set_child(info()); + + return popover; +}; + +const sysInfoFetcher = () => { + if (enabled) { + if (availableFeatures.cpu) { + cpuUtil.set( + "" + + Math.round( + parseFloat(exec(`/bin/fish -c cpu-utilization`)), + ), + ); + } + if (availableFeatures.ram) { + ramUtil.set( + "" + + Math.round( + parseFloat( + exec( + `/bin/bash -c "free | awk '/Mem/ { printf(\\"%.2f\\\\n\\", ($3/$2)*100) }'"`, + ), + ), + ), + ); + ramUsed.set( + exec( + `/bin/bash -c \"free -h | awk '/^Mem:/ {print $3 \\" used of \\" $2}'\"`, + ) + .replaceAll("Gi", "GiB") + .replaceAll("Mi", "MiB"), + ); + } + gpuUtil.set(exec("cat /sys/class/drm/card1/device/gpu_busy_percent")); + } +}; + +const panel = SystemInformationPanel(); + +const SystemInfo = () => { + featureTest(); + + const openSysInfo = async () => { + panel.popup(); + systemStats.set(refreshStats()); + }; + + if (enabled) { + sysInfoFetcher(); + interval(FETCH_INTERVAL, sysInfoFetcher); + + return ( + + ); + } else { + return ; + } +}; + +export default { + SystemInfo, + panel, +}; diff --git a/config/astal/components/bar/ui/modules/stats.d.ts b/config/astal/components/bar/modules/stats.d.ts similarity index 100% rename from config/astal/components/bar/ui/modules/stats.d.ts rename to config/astal/components/bar/modules/stats.d.ts diff --git a/config/astal/components/bar/ui/QuickActions/QuickActions.tsx b/config/astal/components/bar/ui/QuickActions/QuickActions.tsx deleted file mode 100644 index 096af5f..0000000 --- a/config/astal/components/bar/ui/QuickActions/QuickActions.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Gtk } from "astal/gtk4" -import Power from "./modules/Power"; -import Audio from "./modules/Audio/Audio"; -import Bluetooth from "./modules/Bluetooth/Bluetooth"; - -const QuickActions = () => { - const popover = new Gtk.Popover( { cssClasses: [ 'quick-actions-popover' ] } ); - - popover.set_child( createQuickActionMenu() ); - - return popover; -} - - -const createQuickActionMenu = () => { - // TODO: For the future add WiFi / Networking back, for the time being remove, as unnecessary effort - return - - - - -} - - -// TODO: Expose additional functions to be usable through CLI -export default { - QuickActions -}; diff --git a/config/astal/components/bar/ui/QuickActions/modules/Bluetooth/bthelper.ts b/config/astal/components/bar/ui/QuickActions/modules/Bluetooth/bthelper.ts deleted file mode 100644 index e69de29..0000000 diff --git a/config/astal/components/bar/ui/QuickActions/modules/Brightness/Brightness.tsx b/config/astal/components/bar/ui/QuickActions/modules/Brightness/Brightness.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/config/astal/components/bar/ui/QuickActions/modules/Player/Player.tsx b/config/astal/components/bar/ui/QuickActions/modules/Player/Player.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/config/astal/components/bar/ui/QuickActions/quickactions.scss b/config/astal/components/bar/ui/QuickActions/quickactions.scss deleted file mode 100644 index bc4a9b1..0000000 --- a/config/astal/components/bar/ui/QuickActions/quickactions.scss +++ /dev/null @@ -1,13 +0,0 @@ -.title-2 { - font-size: 1.2rem; - font-weight: bold; -} - -.bt-conn-list { - margin-bottom: 20px; -} - -popover>box { - margin: 10px; - border-radius: 50px; -} diff --git a/config/astal/components/bar/ui/bar.scss b/config/astal/components/bar/ui/bar.scss deleted file mode 100644 index 7b19d10..0000000 --- a/config/astal/components/bar/ui/bar.scss +++ /dev/null @@ -1,19 +0,0 @@ -$fg-color: #{"@theme_fg_color"}; -$bg-color: #{"@theme_bg_color"}; - -window.Bar { - background: transparent; - color: $fg-color; - font-weight: bold; - - >centerbox { - background: $bg-color; - border-radius: 10px; - margin: 8px; - } - - button { - border-radius: 8px; - margin: 2px; - } -} diff --git a/config/astal/components/bar/ui/modules/Calendar.tsx b/config/astal/components/bar/ui/modules/Calendar.tsx deleted file mode 100644 index abe16c7..0000000 --- a/config/astal/components/bar/ui/modules/Calendar.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { GLib, Variable } from "astal" -import { Gtk } from "astal/gtk4" - -const Time = ({ format = "%a, %e.%m %H:%M:%S" }) => { - const time = Variable("").poll(1000, () => - GLib.DateTime.new_now_local().format(format)!) - - return - - - - - -} - -const Calendar = () => { - -} - - -export default { - Time -} diff --git a/config/astal/components/bar/ui/modules/Hyprland.tsx b/config/astal/components/bar/ui/modules/Hyprland.tsx deleted file mode 100644 index 0933a78..0000000 --- a/config/astal/components/bar/ui/modules/Hyprland.tsx +++ /dev/null @@ -1,157 +0,0 @@ - -import AstalTray from "gi://AstalTray"; -import { bind, GObject } from "astal"; -import AstalHyprland from "gi://AstalHyprland"; -import { Gtk } from "astal/gtk4"; - -const SYNC = GObject.BindingFlags.SYNC_CREATE; - -const SysTray = () => { - const trayBox = new Gtk.Box(); - const tray = AstalTray.get_default(); - - const trayItems = new Map(); - const trayAddedHandler = tray.connect("item-added", (_, id) => { - const item = tray.get_item(id); - const popover = Gtk.PopoverMenu.new_from_model(item.menu_model); - const icon = new Gtk.Image(); - const button = new Gtk.MenuButton({ popover, child: icon }); - - item.bind_property("gicon", icon, "gicon", SYNC); - popover.insert_action_group("dbusmenu", item.action_group); - item.connect("notify::action-group", () => { - popover.insert_action_group("dbusmenu", item.action_group); - }); - - trayItems.set(id, button); - trayBox.append(button); - }) - - const trayRemovedHandler = tray.connect("item-removed", (_, id) => { - const button = trayItems.get(id); - if (button) { - trayBox.remove(button); - button.run_dispose(); - trayItems.delete(id); - } - }); - - trayBox.connect("destroy", () => { - tray.disconnect(trayAddedHandler); - tray.disconnect(trayRemovedHandler); - }); - - return trayBox; -} - - -const Workspace = () => { - const hypr = AstalHyprland.get_default() - - return - {bind(hypr, "workspaces").as(wss => wss - .filter(ws => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces - .sort((a, b) => a.id - b.id) - .map(ws => ( - - )) - )} - -} - - -/** - * Displays the name of the currently active window and provides a popover for - * displaying all available clients - */ -const ActiveWindow = () => { - const hypr = AstalHyprland.get_default(); - const focused = bind( hypr, "focusedClient" ); - - const WindowPopover = (): Gtk.Popover => { - // Set up boxes + Popover - const clients = new Map(); - const popover = new Gtk.Popover(); - const popoverBox = new Gtk.Box( { orientation: Gtk.Orientation.VERTICAL } ); - - const addClient = ( client: AstalHyprland.Client ) => { - const clientBox = new Gtk.Box(); - - // Workspace description - const descWS = new Gtk.Label( { label: '(WS ' } ); - - // Workpsace information - const workspace = new Gtk.Label(); - client.workspace.bind_property( 'name', workspace, 'label', SYNC ); - - const windowClassDesc = new Gtk.Label( { label: ') [' } ); - - const windowClass = new Gtk.Label(); - windowClass.label = client.get_initial_class(); - - const titleDesc = new Gtk.Label( { label: '] ' } ); - titleDesc.set_margin_end( 2 ); - - const title = new Gtk.Label(); - client.bind_property( 'title', title, 'label', SYNC ); - - clientBox.append( descWS ); - clientBox.append( workspace ); - clientBox.append( windowClassDesc ); - clientBox.append( windowClass ); - clientBox.append( titleDesc ); - clientBox.append( title ); - - popoverBox.append( clientBox ); - - clients.set( client.get_address(), clientBox ); - } - - // Populate with already added clients - const c = hypr.get_clients(); - for ( let index = 0; index < c.length; index++ ) { - addClient( c[ index ] ); - } - - hypr.connect( 'client-added', ( _, client ) => { - addClient( client ); - } ); - - hypr.connect( 'client-removed', ( _, client ) => { - const c = clients.get( client ); - if ( c ) { - popoverBox.remove( c ); - c.run_dispose(); - clients.delete( client ); - } - } ); - - popover.set_child( popoverBox ); - return popover; - } - - const windowPopover = WindowPopover(); - - // ─────────────────────────────────────────────────────────────────── - // Return fully assembled HyprlandFocusedClient box - // ─────────────────────────────────────────────────────────────────── - return - - { windowPopover } - -} - - -export default { - Workspace, - ActiveWindow, - SysTray -} diff --git a/config/astal/components/bar/ui/modules/QuickView.tsx b/config/astal/components/bar/ui/modules/QuickView.tsx deleted file mode 100644 index f6f7d42..0000000 --- a/config/astal/components/bar/ui/modules/QuickView.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { bind } from "astal"; -import AstalBattery from "gi://AstalBattery"; -import AstalBluetooth from "gi://AstalBluetooth"; -import AstalNetwork from "gi://AstalNetwork" -import AstalWp from "gi://AstalWp"; -import Brightness from "../../util/brightness"; -import { Gtk } from "astal/gtk4"; -import QuickActions from "../QuickActions/QuickActions"; - -const STATE = AstalNetwork.DeviceState; - - -const QuickView = () => { - const quickActions = QuickActions.QuickActions(); - - return -} - - -const NetworkWidget = () => { - const network = AstalNetwork.get_default(); - - return - { - if ( state === AstalNetwork.State.CONNECTING ) { - return 'chronometer-reset-symbolic'; - } else if ( state === AstalNetwork.State.CONNECTED_LOCAL || state === AstalNetwork.State.CONNECTED_SITE || state === AstalNetwork.State.CONNECTED_GLOBAL ) { - return 'network-wired-activated-symbolic'; - } else { - return 'paint-unknown-symbolic'; - } - } )} cssClasses={[ 'network-widget', 'quick-view-symbol' ]} visible={bind( network.wifi, 'state' ).as( state => state !== STATE.ACTIVATED )}> - { - if ( state === STATE.ACTIVATED ) { - return network.wifi.iconName - } else { - return ''; - } - } )} cssClasses={[ 'network-widget', 'quick-view-symbol' ]} visible={bind( network.wifi, 'state' ).as( state => state === STATE.ACTIVATED )}> - - - -} - -const BluetoothWidget = () => { - const bluetooth = AstalBluetooth.get_default(); - const enabled = bind( bluetooth.adapter, "powered" ); - const connected = bind( bluetooth, "isConnected" ); - - // For each connected BT device, render status - return - e )}> - c )}> - !c )}> - - !e )}> - - {bind( bluetooth, 'devices' ).as( devices => { - return devices.map( device => { - return c )}> - icon )}> - - - } ); - } )} - - -} - - -const BatteryWidget = () => { - const battery = AstalBattery.get_default(); - if ( battery.get_is_present() ) { - return icon )} cssClasses={[ 'quick-view-symbol' ]}> - } else { - return - } - // Else, no battery available -> Don't show the widget -} - - -const BrightnessWidget = () => { - const brightness = Brightness.get_default(); - const screen_brightness = bind( brightness, "screen" ); - - return -} - - -const Audio = () => { - const wireplumber = AstalWp.get_default(); - if ( wireplumber ) { - return - icon )} cssClasses={[ 'quick-view-symbol' ]}> - icon )} cssClasses={[ 'quick-view-symbol' ]}> - - } else { - print( '[ WirePlumber ] Could not connect, Audio support in bar will be missing' ); - return ; - } -} - -// cssClasses={[ 'quick-view-symbol' ]} - -export default { - QuickView -} diff --git a/config/astal/components/bar/ui/modules/SystemInfo.tsx b/config/astal/components/bar/ui/modules/SystemInfo.tsx deleted file mode 100644 index d909b2c..0000000 --- a/config/astal/components/bar/ui/modules/SystemInfo.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { exec, GLib, interval, Variable } from "astal" -import { Gtk } from "astal/gtk4"; -import AstalBattery from "gi://AstalBattery?version=0.1"; - - -const FETCH_INTERVAL = 2000; - - -const cpuUtil = Variable( '0%' ); -const ramUtil = Variable( '0%' ); -const ramUsed = Variable( '0MiB' ); -const gpuUtil = Variable( '0%' ); -let gpuName = 'card1'; -let enabled = false; - -const refreshStats = (): Stats => { - gpuName = exec( `/bin/bash -c "ls /sys/class/drm/ | grep '^card[0-9]*$'"` ); - const cpuNameInSensors = 'CPUTIN' - const stats = { - kernel: exec( 'uname -sr' ), - netSpeed: exec( `/bin/bash -c "interface=$(ip route get 8.8.8.8 | awk '{print $5; exit}') && cat \"/sys/class/net/$interface/speed\""` ), - cpuTemp: exec( `/bin/bash -c "sensors | grep -m1 ${cpuNameInSensors} | awk '{print $2}'"` ), - cpuClk: exec( `awk '/cpu MHz/ {sum+=$4; ++n} END {print sum/n " MHz"}' /proc/cpuinfo` ), - gpuTemp: exec( `/bin/bash -c "sensors | grep -E 'edge' | awk '{print $2}'"` ), - gpuClk: exec( `/bin/bash -c "cat /sys/class/drm/${gpuName}/device/pp_dpm_sclk | grep '\\*' | awk '{print $2 $3}'"` ), - vram: Math.round( parseInt( exec( `cat /sys/class/drm/${gpuName}/device/mem_info_vram_used` ) ) / 1024 / 1024 ) + 'MiB', - availableVRAM: Math.round( parseInt( exec( `cat /sys/class/drm/${gpuName}/device/mem_info_vram_total` ) ) / 1024 / 1024 ) + 'MiB', - } - - return stats; -} - -const systemStats: Variable = Variable( refreshStats() ); - - -const availableFeatures = { - cpu: true, - ram: true, -} - - -const featureTest = () => { - // Check if awk & sed are available - try { - exec( 'awk -V' ); - exec( 'sed --version' ); - enabled = true; - } catch ( e ) { - printerr( '[ SysInfo ] AWK or SED missing! No system info will be available' ); - enabled = false; - return; - } - - // Check if mpstat is available - try { - exec( 'mpstat -V' ); - } catch ( e ) { - availableFeatures.cpu = false; - printerr( '[ SysInfo ] Feature Test for CPU info failed. mpstat from the sysstat package missing!' ); - } -} - -const info = () => { - return - - - ; -} - - -const SystemInformationPanel = () => { - const popover = new Gtk.Popover(); - - popover.set_child( info() ); - - return popover; -} - - -const sysInfoFetcher = () => { - if ( enabled ) { - if ( availableFeatures.cpu ) { - cpuUtil.set( '' + Math.round( parseFloat( exec( `/bin/fish -c cpu-utilization` ) ) ) ); - } - if ( availableFeatures.ram ) { - ramUtil.set( '' + Math.round( parseFloat( exec( `/bin/bash -c "free | awk '/Mem/ { printf(\\"%.2f\\\\n\\", ($3/$2)*100) }'"` ) ) ) ); - ramUsed.set( exec( `/bin/bash -c \"free -h | awk '/^Mem:/ {print $3 \\" used of \\" $2}'\"` ).replaceAll( 'Gi', 'GiB' ).replaceAll( 'Mi', 'MiB' ) ); - } - gpuUtil.set( exec( 'cat /sys/class/drm/card1/device/gpu_busy_percent' ) ); - } -} - - -const panel = SystemInformationPanel(); - - -const SystemInfo = () => { - featureTest(); - - const openSysInfo = async () => { - panel.popup(); - systemStats.set( refreshStats() ); - } - - if ( enabled ) { - sysInfoFetcher(); - interval( FETCH_INTERVAL, sysInfoFetcher ); - - return - } else { - return - } -} - - -export default { - SystemInfo, - panel -} diff --git a/config/astal/components/bar/util/sysinfo.ts b/config/astal/components/bar/util/sysinfo.ts deleted file mode 100644 index e69de29..0000000 diff --git a/config/astal/no-avatar-icon.jpg b/config/astal/no-avatar-icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87ecabf4682978993bd77e34b354d5cea12c0543 GIT binary patch literal 8853 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