From 9649ab0b6ed9dac81b7f3be14b1806d3e1d60615 Mon Sep 17 00:00:00 2001 From: tux Date: Wed, 24 Sep 2025 16:39:34 +0530 Subject: [PATCH] feat: migrate to ags v3 --- .gitignore | 1 + app.ts | 10 +- flake.lock | 39 ++----- flake.nix | 72 +++++++----- handler.ts | 14 --- package-lock.json | 35 ------ package.json | 7 -- tsconfig.json | 22 ++-- widgets/app-launcher/index.tsx | 69 ++++++------ widgets/bar/battery.tsx | 27 +++-- widgets/bar/cpu.tsx | 6 +- widgets/bar/gpu.tsx | 6 +- widgets/bar/index.tsx | 67 +++++------ widgets/bar/launcher.tsx | 6 +- widgets/bar/network.tsx | 17 +-- widgets/bar/profile.tsx | 6 +- widgets/bar/tailscale.tsx | 7 +- widgets/bar/time.tsx | 10 +- widgets/bar/tray.tsx | 13 +-- widgets/bar/workspace.tsx | 41 +++---- widgets/common/index.ts | 1 - widgets/common/picture.tsx | 11 -- widgets/notifications/icon.tsx | 21 ---- widgets/notifications/index.tsx | 45 ++++++-- widgets/notifications/notifd.ts | 79 ------------- widgets/notifications/notification.tsx | 149 +++++++++++++++++-------- 26 files changed, 330 insertions(+), 451 deletions(-) delete mode 100644 handler.ts delete mode 100644 package-lock.json delete mode 100644 package.json delete mode 100644 widgets/common/index.ts delete mode 100644 widgets/common/picture.tsx delete mode 100644 widgets/notifications/icon.tsx delete mode 100644 widgets/notifications/notifd.ts diff --git a/.gitignore b/.gitignore index 298eb4d..8456525 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ @girs/ +env.d.ts diff --git a/app.ts b/app.ts index 6ed1e1a..b901b12 100644 --- a/app.ts +++ b/app.ts @@ -1,16 +1,14 @@ -import { App } from "astal/gtk4"; +import app from "ags/gtk4/app"; +import GLib from "gi://GLib"; import style from "./style.scss"; import windows from "./windows"; -import GLib from "gi://GLib"; -import { reqHandler } from "./handler"; const icons = `${GLib.get_user_config_dir()}/tpanel/assets/icons`; -App.start({ +app.start({ css: style, icons: icons, - requestHandler: reqHandler, main() { - windows.map((win) => App.get_monitors().map(win)); + windows.map((win) => app.get_monitors().map(win)); }, }); diff --git a/flake.lock b/flake.lock index 4ceda29..02d8e82 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ ] }, "locked": { - "lastModified": 1744557573, - "narHash": "sha256-XAyj0iDuI51BytJ1PwN53uLpzTDdznPDQFG4RwihlTQ=", + "lastModified": 1758577685, + "narHash": "sha256-iHT0kvsQJG+Z89quGi7rNCXEg2e3DBGfuuCMu/UwiIo=", "owner": "aylur", "repo": "ags", - "rev": "3ed9737bdbc8fc7a7c7ceef2165c9109f336bff6", + "rev": "aa7a8a2dd6e54aaeb4e13a73ed3bc2283995090b", "type": "github" }, "original": { @@ -29,31 +29,11 @@ ] }, "locked": { - "lastModified": 1742571008, - "narHash": "sha256-5WgfJAeBpxiKbTR/gJvxrGYfqQRge5aUDcGKmU1YZ1Q=", + "lastModified": 1756474652, + "narHash": "sha256-iiBU6itpEqE0spXeNJ3uJTfioSyKYjt5bNepykpDXTE=", "owner": "aylur", "repo": "astal", - "rev": "dc0e5d37abe9424c53dcbd2506a4886ffee6296e", - "type": "github" - }, - "original": { - "owner": "aylur", - "repo": "astal", - "type": "github" - } - }, - "astal_2": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1748416910, - "narHash": "sha256-FEQcs58HL8Fe4i7XlqVEUwthjxwvRvgX15gTTfW17sU=", - "owner": "aylur", - "repo": "astal", - "rev": "c1bd89a47c81c66ab5fc6872db5a916c0433fb89", + "rev": "20bd8318e4136fbd3d4eb2d64dbabc3acbc915dd", "type": "github" }, "original": { @@ -64,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1748026106, - "narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=", + "lastModified": 1758427187, + "narHash": "sha256-pHpxZ/IyCwoTQPtFIAG2QaxuSm8jWzrzBGjwQZIttJc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "063f43f2dbdef86376cc29ad646c45c46e93234c", + "rev": "554be6495561ff07b6c724047bdd7e0716aa7b46", "type": "github" }, "original": { @@ -81,7 +61,6 @@ "root": { "inputs": { "ags": "ags", - "astal": "astal_2", "nixpkgs": "nixpkgs" } } diff --git a/flake.nix b/flake.nix index c135a9d..9c4a99e 100644 --- a/flake.nix +++ b/flake.nix @@ -1,11 +1,9 @@ { description = "tux's widgets for wayland"; + inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; - astal = { - url = "github:aylur/astal"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + ags = { url = "github:aylur/ags"; inputs.nixpkgs.follows = "nixpkgs"; @@ -15,29 +13,54 @@ outputs = { self, nixpkgs, - astal, ags, }: let system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; + pname = "tpanel"; + entry = "app.ts"; + + agsPackages = with ags.packages.${system}; [ + io + astal4 + hyprland + apps + battery + tray + network + notifd + ]; + + extraPackages = + agsPackages + ++ [ + pkgs.libadwaita + ]; in { packages.${system} = { default = let - tpanel = ags.lib.bundle { - inherit pkgs; + tpanel = pkgs.stdenv.mkDerivation { + name = pname; src = ./.; - name = "tpanel"; - entry = "app.ts"; - gtk4 = true; - extraPackages = with ags.packages.${system}; [ - hyprland - apps - battery - tray - network - notifd + nativeBuildInputs = with pkgs; [ + wrapGAppsHook + gobject-introspection + ags.packages.${system}.default ]; + + buildInputs = extraPackages ++ [pkgs.gjs]; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin + mkdir -p $out/share + cp -r * $out/share + ags bundle ${entry} $out/bin/${pname} -d "SRC='$out/share'" + + runHook postInstall + ''; }; in pkgs.runCommand "tpanel" { @@ -67,7 +90,7 @@ ''; - astal = astal.packages.${system}; + ags = ags.packages.${system}; }; apps.default = { @@ -77,20 +100,9 @@ devShells.${system} = { default = pkgs.mkShell { - nativeBuildInputs = [ - astal.packages.${system}.default - ]; buildInputs = [ - # includes astal3 astal4 astal-io by default (ags.packages.${system}.default.override { - extraPackages = with ags.packages.${system}; [ - hyprland - apps - battery - tray - network - notifd - ]; + inherit extraPackages; }) ]; }; diff --git a/handler.ts b/handler.ts deleted file mode 100644 index 174d870..0000000 --- a/handler.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { App } from "astal/gtk4"; -import { WINDOW_NAME } from "./widgets/bar"; - -export const reqHandler = (req: string, res: (res: any) => void) => { - switch (req) { - case "toggle-bar": - const win = App.get_window(WINDOW_NAME); - win?.is_visible() ? win.hide() : win?.set_visible(true); - break; - - default: - res("uknown command"); - } -}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 98d7200..0000000 --- a/package-lock.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "astal-shell", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "astal-shell", - "dependencies": { - "astal": "/nix/store/8cl58ip2nasg6rdyj59cwg2f0qbixs28-astal-gjs/share/astal/gjs", - "typescript": "^5.7.3" - } - }, - "../../../../nix/store/8cl58ip2nasg6rdyj59cwg2f0qbixs28-astal-gjs/share/astal/gjs": { - "name": "astal", - "license": "LGPL-2.1" - }, - "node_modules/astal": { - "resolved": "../../../../nix/store/8cl58ip2nasg6rdyj59cwg2f0qbixs28-astal-gjs/share/astal/gjs", - "link": true - }, - "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 74960ce..0000000 --- a/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "astal-shell", - "dependencies": { - "astal": "/nix/store/8cl58ip2nasg6rdyj59cwg2f0qbixs28-astal-gjs/share/astal/gjs", - "typescript": "^5.7.3" - } -} diff --git a/tsconfig.json b/tsconfig.json index a92bc43..9078586 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,10 @@ { - "$schema": "https://json.schemastore.org/tsconfig", - "compilerOptions": { - "experimentalDecorators": true, - "strict": true, - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "Bundler", - // "checkJs": true, - // "allowJs": true, - "jsx": "react-jsx", - "jsxImportSource": "astal/gtk4", - } -} + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "ags/gtk4", + "module": "ES2022", + "moduleResolution": "Bundler", + "strict": true, + "target": "ES2020" + } +} \ No newline at end of file diff --git a/widgets/app-launcher/index.tsx b/widgets/app-launcher/index.tsx index a636f60..643bc2d 100644 --- a/widgets/app-launcher/index.tsx +++ b/widgets/app-launcher/index.tsx @@ -1,13 +1,16 @@ -import { Variable } from "astal"; -import { App, Astal, Gdk, Gtk, hook } from "astal/gtk4"; +import { createState, For } from "ags"; +import { Astal, Gdk, Gtk } from "ags/gtk4"; +import app from "ags/gtk4/app"; import AstalApps from "gi://AstalApps"; export const WINDOW_NAME = "app-launcher"; + +let searchEntry: Gtk.Entry; const apps = new AstalApps.Apps(); -const text = Variable(""); +const [searchText, setSearchText] = createState(""); const hide = () => { - App.get_window(WINDOW_NAME)?.set_visible(false); + app.get_window(WINDOW_NAME)?.set_visible(false); }; const AppButton = ({ app }: { app: AstalApps.Application }) => { @@ -29,42 +32,29 @@ const AppButton = ({ app }: { app: AstalApps.Application }) => { }; const AppList = () => { - const appList = text((text) => apps.fuzzy_query(text)); + const appList = searchText((text) => apps.fuzzy_query(text)); return ( - - {appList.as((list) => list.map((app) => ))} + + {(app) => } ); }; const AppSearch = () => { - const onEnter = () => { - apps.fuzzy_query(text.get())?.[0].launch(); - hide(); - }; return ( (searchEntry = ref)} cssClasses={["search"]} - vexpand - text={text.get()} + text={searchText} placeholderText="Search..." - onChanged={(self) => text.set(self.text)} - onActivate={onEnter} - setup={(self) => { - hook(self, App, "window-toggled", (_, win) => { - const winName = win.name; - const visible = win.visible; - - if (winName == WINDOW_NAME && visible) { - text.set(""); - self.set_text(""); - self.grab_focus(); - } - }); - }} + onNotifyText={({ text }) => setSearchText(text)} /> ); }; @@ -75,16 +65,17 @@ export const AppLauncher = (gdkmonitor: Gdk.Monitor) => { name={WINDOW_NAME} cssClasses={["app-launcher"]} gdkmonitor={gdkmonitor} + application={app} exclusivity={Astal.Exclusivity.EXCLUSIVE} - application={App} keymode={Astal.Keymode.ON_DEMAND} - onKeyPressed={(_, keyval) => { - if (keyval === Gdk.KEY_Escape) { - App.toggle_window(WINDOW_NAME); - } + onNotifyVisible={({ visible }) => { + if (visible) searchEntry.grab_focus(); + else searchEntry.set_text(""); }} > - + + + @@ -92,3 +83,15 @@ export const AppLauncher = (gdkmonitor: Gdk.Monitor) => { ); }; + +const onKey = ( + _e: Gtk.EventControllerKey, + keyval: number, + _: number, + mod: number, +) => { + if (keyval === Gdk.KEY_Escape) { + app.toggle_window(WINDOW_NAME); + return; + } +}; diff --git a/widgets/bar/battery.tsx b/widgets/bar/battery.tsx index 3d992c3..525d8db 100644 --- a/widgets/bar/battery.tsx +++ b/widgets/bar/battery.tsx @@ -1,14 +1,15 @@ -import { bind, Variable } from "astal"; +import { createBinding, createComputed } from "ags"; import AstalBattery from "gi://AstalBattery"; export const Battery = () => { const battery = AstalBattery.get_default(); - const chargingIcon = Variable.derive( - [ - bind(battery, "percentage"), - bind(battery, "charging"), - bind(battery, "state"), - ], + + const percentage = createBinding(battery, "percentage"); + const charging = createBinding(battery, "charging"); + const state = createBinding(battery, "state"); + + const chargingIcon = createComputed( + [percentage, charging, state], (percentage, charging, state) => { const batFull = state === AstalBattery.State.FULLY_CHARGED; const p = percentage * 100; @@ -21,11 +22,13 @@ export const Battery = () => { ); return ( - - chargingIcon.drop()} /> -