nixos/config/ags/widget/Bar.tsx

173 lines
4.7 KiB
TypeScript
Raw Normal View History

2024-11-15 23:24:58 +04:00
import { App } from "astal/gtk3"
import { Variable, GLib, bind } from "astal"
import { Astal, Gtk, Gdk } from "astal/gtk3"
import Hyprland from "gi://AstalHyprland"
import Mpris from "gi://AstalMpris"
import Battery from "gi://AstalBattery"
import Wp from "gi://AstalWp"
import Network from "gi://AstalNetwork"
import Tray from "gi://AstalTray"
function SysTray() {
const tray = Tray.get_default()
return <box className="TrayMenu">
{bind(tray, "items").as(items => items.map(item => {
if (item.iconThemePath)
App.add_icons(item.iconThemePath)
const menu = item.create_menu()
return <button
className="TrayIcon"
tooltipMarkup={bind(item, "tooltipMarkup")}
onDestroy={() => menu?.destroy()}
onClickRelease={self => {
menu?.popup_at_widget(self, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null)
}}>
<icon gIcon={bind(item, "gicon")} />
</button>
}))}
</box>
}
function Wifi() {
const { wifi } = Network.get_default()
return <icon
tooltipText={bind(wifi, "ssid").as(String)}
className="Wifi"
icon={bind(wifi, "iconName")}
/>
}
function AudioSlider() {
const speaker = Wp.get_default()?.audio.defaultSpeaker!
return <box className="AudioSlider" css="min-width: 140px">
<icon icon={bind(speaker, "volumeIcon")} />
<slider
hexpand
onDragged={({ value }) => speaker.volume = value}
value={bind(speaker, "volume")}
/>
</box>
}
function AudioPercent() {
const speaker = Wp.get_default()?.audio.defaultSpeaker!
return <box className="AudioPrecent">
<icon icon={bind(speaker, "volumeIcon")}/>
<label label={bind(speaker, "volume").as(p =>
`${Math.round(p * 100)} %`
)}/>
</box>
}
function BatteryLevel() {
const bat = Battery.get_default()
return <box className="Battery"
visible={bind(bat, "isPresent")}>
<icon icon={bind(bat, "batteryIconName")} />
<label label={bind(bat, "percentage").as(p =>
`${Math.floor(p * 100)} %`
)} />
</box>
}
function Media() {
const mpris = Mpris.get_default()
return <box className="Media">
{bind(mpris, "players").as(ps => ps[0] ? (
<box>
<box
className="Cover"
valign={Gtk.Align.CENTER}
css={bind(ps[0], "coverArt").as(cover =>
`background-image: url('${cover}');`
)}
/>
<label
label={bind(ps[0], "title").as(() =>
`${ps[0].title} - ${ps[0].artist}`
)}
/>
</box>
) : (
"Nothing Playing"
))}
</box>
}
function Workspaces() {
const hypr = Hyprland.get_default()
return <box className="Workspaces">
{bind(hypr, "workspaces").as(wss => wss
.sort((a, b) => a.id - b.id)
.map(ws => (
<button
className={bind(hypr, "focusedWorkspace").as(fw =>
ws === fw ? "focused" : "")}
onClicked={() => ws.focus()}>
{ws.id}
</button>
))
)}
</box>
}
function FocusedClient() {
const hypr = Hyprland.get_default()
const focused = bind(hypr, "focusedClient")
return <box
className="Focused"
visible={focused.as(Boolean)}>
{focused.as(client => (
client && <label label={bind(client, "title").as(String)} />
))}
</box>
}
function Time({ format = "%H:%M - %A %e." }) {
const time = Variable<string>("").poll(1000, () =>
GLib.DateTime.new_now_local().format(format)!)
return <label
className="Time"
onDestroy={() => time.drop()}
label={time()}
/>
}
export default function Bar(monitor: Gdk.Monitor) {
const anchor = Astal.WindowAnchor.TOP
| Astal.WindowAnchor.LEFT
| Astal.WindowAnchor.RIGHT
return <window
className="Bar"
gdkmonitor={monitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE}
anchor={anchor}>
<centerbox>
<box hexpand halign={Gtk.Align.START}>
<Workspaces />
<FocusedClient />
</box>
<box>
2024-11-16 16:03:01 +04:00
</box>
<box className="right" hexpand halign={Gtk.Align.END} >
2024-11-15 23:24:58 +04:00
<SysTray />
<AudioPercent/>
<BatteryLevel />
<Time />
</box>
</centerbox>
</window>
}