diff --git a/flake.lock b/flake.lock
index bd25a2b..fb750c4 100644
--- a/flake.lock
+++ b/flake.lock
@@ -42,6 +42,26 @@
"type": "github"
}
},
+ "matcha": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1738448307,
+ "narHash": "sha256-jRmfa28gVEDyS7We881BJDpr6L1kla0AgpEWjZ04tZo=",
+ "ref": "refs/heads/main",
+ "rev": "90721110060e6b870839df847601d79f9a7a6461",
+ "revCount": 28,
+ "type": "git",
+ "url": "https://codeberg.org/QuincePie/matcha"
+ },
+ "original": {
+ "type": "git",
+ "url": "https://codeberg.org/QuincePie/matcha"
+ }
+ },
"nixpkgs": {
"locked": {
"lastModified": 1739020877,
@@ -61,6 +81,7 @@
"root": {
"inputs": {
"ags": "ags",
+ "matcha": "matcha",
"nixpkgs": "nixpkgs"
}
}
diff --git a/flake.nix b/flake.nix
index 87d0bab..4fd569c 100644
--- a/flake.nix
+++ b/flake.nix
@@ -8,17 +8,24 @@
url = "github:aylur/ags";
inputs.nixpkgs.follows = "nixpkgs";
};
+
+ matcha = {
+ url = "git+https://codeberg.org/QuincePie/matcha";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
};
outputs = {
self,
nixpkgs,
ags,
+ matcha,
}: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
astalPkgs = with ags.packages.${system}; [
battery
+ bluetooth
hyprland
mpris
network
@@ -47,6 +54,7 @@
extraPackages = astalPkgs;
})
pkgs.brightnessctl
+ matcha.packages.${pkgs.system}.default
];
};
};
diff --git a/style.scss b/style.scss
index 9171159..dc3fabd 100644
--- a/style.scss
+++ b/style.scss
@@ -34,6 +34,13 @@ $accent: #{"@accent_color"};
}
}
+ .Time {
+ calendar {
+ label:selected {
+ background-color: $accent;
+ }
+ }
+ }
.Battery label {
margin-left: 0;
}
@@ -42,11 +49,29 @@ $accent: #{"@accent_color"};
image {
-gtk-icon-size: 1.2em;
}
-
- menubutton box {
+ .Audio,
+ .Wifi {
margin-right: 0.5em;
- &:last-child {
- margin-right: 0;
+ }
+
+ popover {
+ min-width: 350px;
+
+ .Toggles {
+ margin: 0.5em 0;
+ button image {
+ -gtk-icon-size: 3em;
+ }
+ }
+ trough highlight {
+ background-color: $accent;
+ border-radius: 2em;
+ }
+
+ slider {
+ min-height: 1.7em;
+ min-width: 1.7em;
+ margin: -0.2em;
}
}
}
@@ -59,6 +84,6 @@ $accent: #{"@accent_color"};
}
popover {
- margin-top: 0.5em;
+ margin-top: 0.8em;
}
}
diff --git a/widget/Bar.tsx b/widget/Bar.tsx
index b560406..85bf6f0 100644
--- a/widget/Bar.tsx
+++ b/widget/Bar.tsx
@@ -1,14 +1,18 @@
import { Astal, Gtk, Gdk } from "astal/gtk4";
-import { Variable, GLib, bind } from "astal";
+import { Variable, GLib, bind, execAsync, exec } from "astal";
import Battery from "gi://AstalBattery";
+import Bluetooth from "gi://AstalBluetooth";
import Wp from "gi://AstalWp";
import Network from "gi://AstalNetwork";
import Hyprland from "gi://AstalHyprland";
+import Brightness from "../service/brightness";
+
+const network = Network.get_default();
+const wifi = bind(network, "wifi");
+const hypr = Hyprland.get_default();
+const bluetooth = Bluetooth.get_default();
function Wifi() {
- const network = Network.get_default();
- const wifi = bind(network, "wifi");
-
return (
{wifi.as(
@@ -31,6 +35,42 @@ function Audio() {
);
}
+function AudioSlider() {
+ const speaker = Wp.get_default()?.audio.defaultSpeaker!;
+
+ return (
+
+
+ {
+ speaker.volume = value;
+ }}
+ value={bind(speaker, "volume")}
+ />
+
+ );
+}
+
+function BrightnessSlider() {
+ const brightness = Brightness.get_default();
+
+ return (
+
+
+ {
+ brightness.screen = value;
+ }}
+ value={bind(brightness, "screen")}
+ />
+
+ );
+}
+
function BatteryLevel() {
const bat = Battery.get_default();
@@ -62,6 +102,29 @@ function Time({ format = "%H:%M - %A %e." }) {
);
}
+function IdleInhibitor() {
+ const icon = Variable(getIcon());
+
+ function getIcon() {
+ const state = exec("matcha --status");
+ const enabled = state.match(/on/g);
+ return enabled ? "my-caffeine-on-symbolic" : "my-caffeine-off-symbolic";
+ }
+
+ function toggle() {
+ exec("matcha --toggle");
+ icon.set(getIcon());
+ }
+
+ return (
+
+
+ );
+}
function QuickSettings() {
return (
@@ -71,15 +134,50 @@ function QuickSettings() {
-
+
+
+
+
+ {wifi.as(
+ (wifi) =>
+ wifi && (
+
+
+
+
+
+
+
+
+
+
+
);
}
function Workspaces() {
- const hypr = Hyprland.get_default();
-
return (
{bind(hypr, "workspaces").as((wss) =>
@@ -118,7 +216,7 @@ export default function Bar(monitor: Gdk.Monitor) {
-
+
diff --git a/widget/Popover.tsx b/widget/Popover.tsx
deleted file mode 100644
index c03f07d..0000000
--- a/widget/Popover.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import { Astal, Gdk, Gtk, Widget } from "astal/gtk4";
-
-const { TOP, BOTTOM, LEFT, RIGHT } = Astal.WindowAnchor;
-
-type PopoverProps = Pick<
- Widget.WindowProps,
- | "name"
- | "namespace"
- | "className"
- | "visible"
- | "child"
- | "marginBottom"
- | "marginTop"
- | "marginLeft"
- | "marginRight"
- | "halign"
- | "valign"
-> & {
- onClose?(self): void;
-};
-
-/**
- * Full screen window widget where you can space the child widget
- * using margins and alignment properties.
- *
- * NOTE: Child widgets will assume they can span across the full window width
- * this means that setting `wrap` or `ellipsize` on labels for example will not work
- * without explicitly setting its `max_width_chars` property.
- * For a workaround see Popover2.tsx
- */
-export default function Popover({
- child,
- marginBottom,
- marginTop,
- marginLeft,
- marginRight,
- halign = Gtk.Align.CENTER,
- valign = Gtk.Align.CENTER,
- onClose,
- ...props
-}: PopoverProps) {
- return (
- {
- if (!self.visible) onClose?.(self);
- }}
- // close when click occurs otside of child
- onButtonPressEvent={(self, event) => {
- const [, _x, _y] = event.get_coords();
- const { x, y, width, height } = self.get_child()!.get_allocation();
-
- const xOut = _x < x || _x > x + width;
- const yOut = _y < y || _y > y + height;
-
- // clicked outside
- if (xOut || yOut) {
- self.visible = false;
- }
- }}
- // close when hitting Escape
- onKeyPressEvent={(self, event: Gdk.Event) => {
- if (event.get_keyval()[1] === Gdk.KEY_Escape) {
- self.visible = false;
- }
- }}
- >
- true}
- // child can be positioned with `halign` `valign` and margins
- expand
- halign={halign}
- valign={valign}
- marginBottom={marginBottom}
- marginTop={marginTop}
- marginStart={marginLeft}
- marginEnd={marginRight}
- >
- {child}
-
-
- );
-}