dotfiles/apps/.config/ags/widget/modules/Tailscale.tsx
End bbf099c078
Add AGS bar, wezterm, and misc configs; exclude KDE private keys
- Add full AGS bar (GTK4/Astal/TypeScript) with all modules
- Add wezterm config
- Add niri config, starship, btop, xdg-portal, fish colors
- Add gitignores for browser caches, JetBrains runtime, AGS node_modules
- Exclude kdeconnect private/certificate pem files
2026-04-12 14:45:39 -07:00

60 lines
1.9 KiB
TypeScript

import { Gtk } from "ags/gtk4"
import { execAsync } from "ags/process"
import { interval } from "ags/time"
import { createState } from "ags"
export default function Tailscale() {
const [status, setStatus] = createState({ up: false, ip: "", peers: 0 })
function poll() {
execAsync("tailscale status --json").then(out => {
try {
const j = JSON.parse(out)
setStatus({
up: j.BackendState === "Running",
ip: j.TailscaleIPs?.[0] ?? "",
peers: Object.keys(j.Peer ?? {}).length,
})
} catch {}
}).catch(() => {})
}
poll()
interval(5000, poll)
const popover = new Gtk.Popover()
popover.set_has_arrow(false)
const content = (
<box orientation={Gtk.Orientation.VERTICAL} spacing={8} widthRequest={200}>
<label label={status(s => s.up ? "󰩠 Running" : "󰩠 Stopped")} xalign={0} class="vpn-status-label" />
<label label={status(s => s.ip ? `IP: ${s.ip}` : "No IP")} xalign={0} class="vpn-detail" />
<label label={status(s => `Peers: ${s.peers}`)} xalign={0} class="vpn-detail" />
</box>
) as unknown as Gtk.Widget
popover.set_child(content)
const icon = new Gtk.Image({ iconName: "tailscale", pixelSize: 16 })
const btn = (
<button class={status(s => `module tailscale-module${s.up ? " on" : " off"}`)}
valign={Gtk.Align.CENTER}
onClicked={() => execAsync(
status().up
? "tailscale down"
: `bash -c "tailscale up && sudo ip route add 100.64.0.0/10 dev tailscale0 table main && sudo nft insert rule inet mullvad output ip daddr 100.64.0.0/10 accept && sudo nft insert rule inet mullvad output oif tailscale0 accept"`
).then(poll)}>
</button>
) as unknown as Gtk.Button
btn.set_child(icon)
const gesture = new Gtk.GestureClick()
gesture.button = 3
gesture.connect("pressed", () => popover.popup())
btn.add_controller(gesture)
popover.set_parent(btn)
return btn
}