diff --git a/home/christoph/default.nix b/home/christoph/default.nix index 36535d0d..f333de11 100644 --- a/home/christoph/default.nix +++ b/home/christoph/default.nix @@ -39,7 +39,7 @@ rec { }; modules = { - ags.enable = false; # TODO: Configure + ags.enable = true; # TODO: Configure chromium = { enable = true; diff --git a/home/modules/ags/config/.gitignore b/home/modules/ags/config/.gitignore new file mode 100644 index 00000000..298eb4de --- /dev/null +++ b/home/modules/ags/config/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +@girs/ diff --git a/home/modules/ags/config/app.ts b/home/modules/ags/config/app.ts new file mode 100644 index 00000000..7e8cc7c7 --- /dev/null +++ b/home/modules/ags/config/app.ts @@ -0,0 +1,10 @@ +import { App } from "astal/gtk4" +import style from "./style.scss" +import Bar from "./widget/Bar" + +App.start({ + css: style, + main() { + App.get_monitors().map(Bar) + }, +}) diff --git a/home/modules/ags/config/config.js b/home/modules/ags/config/config.js deleted file mode 100644 index 75d5cc52..00000000 --- a/home/modules/ags/config/config.js +++ /dev/null @@ -1,204 +0,0 @@ -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, - }); -} - -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(), Clock(), SysTray()], - }); -} - -function Bar(monitor = 0) { - return Widget.Window({ - name: `bar-${monitor}`, - class_name: "ags_bar", - monitor, - anchor: ["top", "left", "right"], - exclusivity: "exclusive", - child: Widget.CenterBox({ - start_widget: Left(), - center_widget: Center(), - end_widget: Right(), - }), - }); -} - -App.config({ - style: "/home/christoph/.config/ags/style.css", - windows: [Bar(0)], -}); - -export {}; diff --git a/home/modules/ags/config/env.d.ts b/home/modules/ags/config/env.d.ts new file mode 100644 index 00000000..467c0a41 --- /dev/null +++ b/home/modules/ags/config/env.d.ts @@ -0,0 +1,21 @@ +declare const SRC: string + +declare module "inline:*" { + const content: string + export default content +} + +declare module "*.scss" { + const content: string + export default content +} + +declare module "*.blp" { + const content: string + export default content +} + +declare module "*.css" { + const content: string + export default content +} diff --git a/home/modules/ags/config/package.json b/home/modules/ags/config/package.json new file mode 100644 index 00000000..fd273be8 --- /dev/null +++ b/home/modules/ags/config/package.json @@ -0,0 +1,6 @@ +{ + "name": "astal-shell", + "dependencies": { + "astal": "/home/christoph/.local/share/ags" + } +} diff --git a/home/modules/ags/config/style.css b/home/modules/ags/config/style.css deleted file mode 100644 index 29f8fdd4..00000000 --- a/home/modules/ags/config/style.css +++ /dev/null @@ -1,40 +0,0 @@ -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/modules/ags/config/style.scss b/home/modules/ags/config/style.scss new file mode 100644 index 00000000..1d0d3a9f --- /dev/null +++ b/home/modules/ags/config/style.scss @@ -0,0 +1,20 @@ +// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss +$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/home/modules/ags/config/widget/Bar.tsx b/home/modules/ags/config/widget/Bar.tsx new file mode 100644 index 00000000..c2db8c52 --- /dev/null +++ b/home/modules/ags/config/widget/Bar.tsx @@ -0,0 +1,36 @@ +import { App, Astal, Gtk, Gdk } from "astal/gtk4" +import { Variable } from "astal" + +const time = Variable("").poll(1000, "date") + +export default function Bar(gdkmonitor: Gdk.Monitor) { + const { TOP, LEFT, RIGHT } = Astal.WindowAnchor + + return + + + + + + + +} diff --git a/home/modules/ags/default.nix b/home/modules/ags/default.nix index 0966d1c8..dbcebeb0 100644 --- a/home/modules/ags/default.nix +++ b/home/modules/ags/default.nix @@ -1,4 +1,5 @@ { + inputs, config, lib, mylib, @@ -12,14 +13,21 @@ in { config = lib.mkIf ags.enable { programs.ags = { enable = true; - systemd.enable = true; + systemd.enable = false; # TODO: Enable once configured - # configDir = ./config; + # AGS libs go here + extraPackages = []; + + # This should symlink + configDir = ./config; }; + # The ags module doesn't expose the "astal" cli tool + home.packages = [inputs.ags.packages.${pkgs.system}.io]; + home.file = { # NOTE: Keep this symlinked as long as I'm configuring - ".config/ags".source = config.lib.file.mkOutOfStoreSymlink "${config.paths.nixflake}/home/modules/ags/config"; + # ".config/ags".source = config.lib.file.mkOutOfStoreSymlink "${config.paths.nixflake}/home/modules/ags/config"; # LSP typechecking support (use ags --init) # ".config/ags/types".source = config.lib.file.mkOutOfStoreSymlink "${pkgs.ags}/share/com.github.Aylur.ags/types";