From 9fa19cfdeca75c42cfea3fce6e2ffaa6e5b0804b Mon Sep 17 00:00:00 2001 From: joy Date: Tue, 2 Jul 2024 22:18:06 +0200 Subject: [PATCH] update --- home/ags/config.js | 219 ++++++++++++++++++++++++++++++++++++++ home/ags/style.css | 40 +++++++ home/ags/tsconfig.json | 18 ++++ home/ags/types | 1 + home/hyprland/default.nix | 2 +- 5 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 home/ags/config.js create mode 100644 home/ags/style.css create mode 100644 home/ags/tsconfig.json create mode 120000 home/ags/types diff --git a/home/ags/config.js b/home/ags/config.js new file mode 100644 index 0000000..4c0a30b --- /dev/null +++ b/home/ags/config.js @@ -0,0 +1,219 @@ +const hyprland = await Service.import("hyprland") +const notifications = await Service.import("notifications") +const mpris = await Service.import("mpris") +const audio = await Service.import("audio") +const battery = await Service.import("battery") +const systemtray = await Service.import("systemtray") + +const date = Variable("", { + poll: [1000, 'date "+%H:%M:%S %b %e."'], +}) + +// widgets can be only assigned as a child in one container +// so to make a reuseable widget, make it a function +// then you can simply instantiate one by calling it + +function Workspaces() { + const activeId = hyprland.active.workspace.bind("id") + const workspaces = hyprland.bind("workspaces") + .as(ws => ws.map(({ id }) => Widget.Button({ + on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), + child: Widget.Label(`${id}`), + class_name: activeId.as(i => `${i === id ? "focused" : ""}`), + }))) + + return Widget.Box({ + class_name: "workspaces", + children: workspaces, + }) +} + + +function ClientTitle() { + return Widget.Label({ + class_name: "client-title", + label: hyprland.active.client.bind("title"), + }) +} + + +function Clock() { + return Widget.Label({ + class_name: "clock", + label: date.bind(), + }) +} + + +// we don't need dunst or any other notification daemon +// because the Notifications module is a notification daemon itself +function Notification() { + const popups = notifications.bind("popups") + return Widget.Box({ + class_name: "notification", + visible: popups.as(p => p.length > 0), + children: [ + Widget.Icon({ + icon: "preferences-system-notifications-symbolic", + }), + Widget.Label({ + label: popups.as(p => p[0]?.summary || ""), + }), + ], + }) +} + + +function Media() { + const label = Utils.watch("", mpris, "player-changed", () => { + if (mpris.players[0]) { + const { track_artists, track_title } = mpris.players[0] + return `${track_artists.join(", ")} - ${track_title}` + } else { + return "Nothing is playing" + } + }) + + return Widget.Button({ + class_name: "media", + on_primary_click: () => mpris.getPlayer("")?.playPause(), + on_scroll_up: () => mpris.getPlayer("")?.next(), + on_scroll_down: () => mpris.getPlayer("")?.previous(), + child: Widget.Label({ label }), + }) +} + + +function Volume() { + const icons = { + 101: "overamplified", + 67: "high", + 34: "medium", + 1: "low", + 0: "muted", + } + + function getIcon() { + const icon = audio.speaker.is_muted ? 0 : [101, 67, 34, 1, 0].find( + threshold => threshold <= audio.speaker.volume * 100) + + return `audio-volume-${icons[icon]}-symbolic` + } + + const icon = Widget.Icon({ + icon: Utils.watch(getIcon(), audio.speaker, getIcon), + }) + + const slider = Widget.Slider({ + hexpand: true, + draw_value: false, + on_change: ({ value }) => audio.speaker.volume = value, + setup: self => self.hook(audio.speaker, () => { + self.value = audio.speaker.volume || 0 + }), + }) + + return Widget.Box({ + class_name: "volume", + css: "min-width: 180px", + children: [icon, slider], + }) +} + + +function BatteryLabel() { + const value = battery.bind("percent").as(p => p > 0 ? p / 100 : 0) + const icon = battery.bind("percent").as(p => + `battery-level-${Math.floor(p / 10) * 10}-symbolic`) + + return Widget.Box({ + class_name: "battery", + visible: battery.bind("available"), + children: [ + Widget.Icon({ icon }), + Widget.LevelBar({ + widthRequest: 140, + vpack: "center", + value, + }), + ], + }) +} + + +function SysTray() { + const items = systemtray.bind("items") + .as(items => items.map(item => Widget.Button({ + child: Widget.Icon({ icon: item.bind("icon") }), + on_primary_click: (_, event) => item.activate(event), + on_secondary_click: (_, event) => item.openMenu(event), + tooltip_markup: item.bind("tooltip_markup"), + }))) + + return Widget.Box({ + children: items, + }) +} + + +// layout of the bar +function Left() { + return Widget.Box({ + spacing: 8, + children: [ + Workspaces(), + ClientTitle(), + ], + }) +} + +function Center() { + return Widget.Box({ + spacing: 8, + children: [ + Media(), + Notification(), + ], + }) +} + +function Right() { + return Widget.Box({ + hpack: "end", + spacing: 8, + children: [ + Volume(), + BatteryLabel(), + Clock(), + SysTray(), + ], + }) +} + +function Bar(monitor = 0) { + return Widget.Window({ + name: `bar-${monitor}`, // name has to be unique + class_name: "bar", + monitor, + anchor: ["top", "left", "right"], + exclusivity: "exclusive", + child: Widget.CenterBox({ + start_widget: Left(), + center_widget: Center(), + end_widget: Right(), + }), + }) +} + +App.config({ + style: "./style.css", + windows: [ + Bar(), + + // you can call it, for each monitor + // Bar(0), + // Bar(1) + ], +}) + +export { } diff --git a/home/ags/style.css b/home/ags/style.css new file mode 100644 index 0000000..9ac7355 --- /dev/null +++ b/home/ags/style.css @@ -0,0 +1,40 @@ +window.bar { + background-color: @theme_bg_color; + color: @theme_fg_color; +} + +button { + min-width: 0; + padding-top: 0; + padding-bottom: 0; + background-color: transparent; +} + +button:active { + background-color: @theme_selected_bg_color; +} + +button:hover { + border-bottom: 3px solid @theme_fg_color; +} + +label { + font-weight: bold; +} + +.workspaces button.focused { + border-bottom: 3px solid @theme_selected_bg_color; +} + +.client-title { + color: @theme_selected_bg_color; +} + +.notification { + color: yellow; +} + +levelbar block, +highlight { + min-height: 10px; +} diff --git a/home/ags/tsconfig.json b/home/ags/tsconfig.json new file mode 100644 index 0000000..f03f2d1 --- /dev/null +++ b/home/ags/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": [ + "ES2022" + ], + "allowJs": true, + "checkJs": true, + "strict": true, + "noImplicitAny": false, + "baseUrl": ".", + "typeRoots": [ + "./types" + ], + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/home/ags/types b/home/ags/types new file mode 120000 index 0000000..57e271e --- /dev/null +++ b/home/ags/types @@ -0,0 +1 @@ +/home/joy/.local/share/com.github.Aylur.ags/types \ No newline at end of file diff --git a/home/hyprland/default.nix b/home/hyprland/default.nix index 77907bb..716042f 100644 --- a/home/hyprland/default.nix +++ b/home/hyprland/default.nix @@ -37,7 +37,7 @@ "lxqt-policykit-agent &" "swww init &" "swww img ~/nix/home/hyprland/wallpaper.png &" - "waybar &" + "ags -c ~/nix/home/ags/config.js &" "wl-paste --type text --watch cliphist store" "wl-paste --type image --watch cliphist store" "screen -dmS cmus cmus &"