Add AGS battery widget

This commit is contained in:
Joshua Yuen 2026-09-12 02:37:02 -04:00
parent 70b7605475
commit a020bd3f57
Signed by: josh
GPG Key ID: 530DA0331EFE99F5
4 changed files with 93 additions and 3 deletions

View File

@ -44,14 +44,16 @@
.ws:hover,
.volume:hover,
.wifi:hover {
.wifi:hover,
.battery:hover {
background: transparentize($base05, 0.88);
}
.volume icon,
.mute icon,
.wifi icon,
.wifi-header icon {
.wifi-header icon,
.battery icon {
font-size: 16px;
}
@ -156,3 +158,18 @@
.wifi-row:hover {
background: transparentize($base05, 0.88);
}
.battery-percent {
font-size: 1.6em;
font-weight: bold;
}
.battery-level {
font-size: 0.85em;
margin-left: 3px;
}
.battery-status {
font-size: 0.85em;
opacity: 0.7;
}

View File

@ -3,19 +3,23 @@ import Workspaces from "./Workspaces"
import Clock from "./Clock"
import { VolumeWidget } from "./Volume"
import { WifiWidget } from "./Wifi"
import { BatteryWidget } from "./Battery"
export default function Bar(gdkmonitor: Gdk.Monitor) {
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
const volume = VolumeWidget(gdkmonitor)
const wifi = WifiWidget(gdkmonitor)
const battery = BatteryWidget(gdkmonitor)
const right: Array<JSX.Element> = []
if (wifi.button) right.push(wifi.button)
right.push(volume.button)
if (battery.button) right.push(battery.button)
const popups: Array<JSX.Element> = []
if (wifi.popup) popups.push(wifi.popup)
popups.push(volume.popup)
if (battery.popup) popups.push(battery.popup)
return [
(

View File

@ -0,0 +1,69 @@
import AstalBattery from "gi://AstalBattery"
import { Variable, bind } from "astal"
import Dropdown from "./Dropdown"
const battery = AstalBattery.get_default()
const CHARGING = 1
const DISCHARGING = 2
const FULLY_CHARGED = 4
function fmtTime(seconds: number) {
if (!seconds || seconds <= 0) return null
const h = Math.floor(seconds / 3600)
const m = Math.round((seconds % 3600) / 60)
return h > 0 ? `${h}h ${m}m` : `${m}m`
}
const status = Variable.derive(
[bind(battery, "state"), bind(battery, "time-to-empty"), bind(battery, "time-to-full")],
(state, toEmpty, toFull) => {
if (state === FULLY_CHARGED) return "fully charged"
if (state === CHARGING) {
const t = fmtTime(toFull)
return t ? `charging · ${t} to full` : "charging"
}
if (state === DISCHARGING) {
const t = fmtTime(toEmpty)
return t ? `${t} left` : "on battery"
}
return ""
},
)
export function BatteryWidget(gdkmonitor: Gdk.Monitor) {
if (!battery.isBattery) return { button: null, popup: null }
const open = Variable(false)
const button = (
<button
className="battery"
onClicked={() => open.set(!open.get())}
>
<box>
<icon icon={bind(battery, "icon-name")} />
<label
className="battery-level"
label={bind(battery, "percentage").as((p) => `${Math.round(p * 100)}%`)}
/>
</box>
</button>
)
const popup = (
<Dropdown gdkmonitor={gdkmonitor} target={button} open={open} width={180}>
<label
className="battery-percent"
label={bind(battery, "percentage").as((p) => `${Math.round(p * 100)}%`)}
/>
<label
className="battery-status"
label={status()}
visible={status().as((text) => text !== "")}
/>
</Dropdown>
)
return { button, popup }
}

View File

@ -3,6 +3,6 @@
}:
{
services = {
upower.enable = true;
};
}