diff --git a/modules/home/ags/app/widget/Brightness.tsx b/modules/home/ags/app/widget/Brightness.tsx
new file mode 100644
index 0000000..abf0e84
--- /dev/null
+++ b/modules/home/ags/app/widget/Brightness.tsx
@@ -0,0 +1,31 @@
+import { execAsync, Variable, bind } from "astal"
+
+// no astal.brightness lib in nixpkgs: poll brightnessctl for the current
+// level as a 0..1 fraction, pushing changes through brightnessctl set
+const percent = Variable(0).poll(
+ 2000,
+ ["sh", "-c", "echo $(( $(brightnessctl get) * 100 / $(brightnessctl max) ))"],
+ (out) => parseInt(out) / 100,
+)
+
+export function BrightnessRow() {
+ return (
+
+
+ {
+ const pct = Math.round(self.value * 100)
+ percent.set(pct / 100)
+ execAsync(["brightnessctl", "set", `${pct}%`]).catch(
+ console.error,
+ )
+ }}
+ />
+
+ )
+}
diff --git a/modules/home/ags/app/widget/QuickSettings.tsx b/modules/home/ags/app/widget/QuickSettings.tsx
index b36530b..77477bb 100644
--- a/modules/home/ags/app/widget/QuickSettings.tsx
+++ b/modules/home/ags/app/widget/QuickSettings.tsx
@@ -5,6 +5,7 @@ import { execAsync, Variable, bind } from "astal"
import Dropdown from "./Dropdown"
import { wifiIcon, WifiSection } from "./Wifi"
import { bluetoothIndicator, BluetoothSection } from "./Bluetooth"
+import { BrightnessRow } from "./Brightness"
import { batteryIcon, batteryPercent, BatterySection } from "./Battery"
import { NotificationCard } from "./Notifications"
@@ -125,6 +126,7 @@ export default function QuickSettings(gdkmonitor: Gdk.Monitor) {
/>
)}
+