mirror of
https://github.com/tuxdotrs/tpanel.git
synced 2025-10-10 21:01:54 +05:30
refactor: move system info to control center
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
import { Gdk, Gtk } from "ags/gtk4";
|
||||
import { exec } from "ags/process";
|
||||
import { execAsync } from "ags/process";
|
||||
import { createPoll } from "ags/time";
|
||||
import GLib from "gi://GLib";
|
||||
|
||||
export const Header = () => {
|
||||
const { VERTICAL } = Gtk.Orientation;
|
||||
const { CENTER, START, END } = Gtk.Align;
|
||||
|
||||
const time = createPoll(
|
||||
"",
|
||||
1000,
|
||||
() => GLib.DateTime.new_now_local().format("%a %b %d - %I:%M:%S %p")!,
|
||||
);
|
||||
|
||||
return (
|
||||
<box cssClasses={["header"]}>
|
||||
<image
|
||||
@@ -19,20 +26,38 @@ export const Header = () => {
|
||||
<label halign={START} label="@tuxdotrs" />
|
||||
</box>
|
||||
|
||||
<box hexpand halign={END} spacing={10} cssClasses={["controls"]}>
|
||||
<button
|
||||
cursor={Gdk.Cursor.new_from_name("pointer", null)}
|
||||
onClicked={() => exec("hyprlock")}
|
||||
>
|
||||
<image iconName="fa-lock-symbolic" />
|
||||
</button>
|
||||
<box
|
||||
hexpand
|
||||
halign={END}
|
||||
valign={CENTER}
|
||||
spacing={10}
|
||||
cssClasses={["controls"]}
|
||||
orientation={VERTICAL}
|
||||
>
|
||||
<box spacing={10} homogeneous>
|
||||
<button
|
||||
cursor={Gdk.Cursor.new_from_name("pointer", null)}
|
||||
onClicked={() => execAsync("flameshot launcher")}
|
||||
>
|
||||
<image iconName="fa-screenshot-symbolic" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
cursor={Gdk.Cursor.new_from_name("pointer", null)}
|
||||
onClicked={() => exec("poweroff")}
|
||||
>
|
||||
<image iconName="fa-power-symbolic" />
|
||||
</button>
|
||||
<button
|
||||
cursor={Gdk.Cursor.new_from_name("pointer", null)}
|
||||
onClicked={() => execAsync("hyprlock")}
|
||||
>
|
||||
<image iconName="fa-lock-symbolic" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
cursor={Gdk.Cursor.new_from_name("pointer", null)}
|
||||
onClicked={() => execAsync("poweroff")}
|
||||
>
|
||||
<image iconName="fa-power-symbolic" />
|
||||
</button>
|
||||
</box>
|
||||
|
||||
<label label={time} />
|
||||
</box>
|
||||
</box>
|
||||
);
|
||||
|
@@ -4,6 +4,7 @@ import { Footer } from "./footer";
|
||||
import { Header } from "./header";
|
||||
import { NotificationList } from "./notification-list";
|
||||
import { SlidingControls } from "./sliding-controls";
|
||||
import { SystemInfo } from "./system-info";
|
||||
|
||||
export const WINDOW_NAME = "control-center";
|
||||
|
||||
@@ -14,6 +15,7 @@ export const ControlCenter = (gdkmonitor: Gdk.Monitor) => {
|
||||
return (
|
||||
<window
|
||||
name={WINDOW_NAME}
|
||||
visible
|
||||
cssClasses={["control-center"]}
|
||||
gdkmonitor={gdkmonitor}
|
||||
application={app}
|
||||
@@ -24,6 +26,7 @@ export const ControlCenter = (gdkmonitor: Gdk.Monitor) => {
|
||||
<box vexpand orientation={VERTICAL} spacing={20}>
|
||||
<Header />
|
||||
<SlidingControls />
|
||||
<SystemInfo />
|
||||
<NotificationList />
|
||||
<Footer />
|
||||
</box>
|
||||
|
143
widgets/control-center/system-info.tsx
Normal file
143
widgets/control-center/system-info.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import { createBinding, createComputed } from "ags";
|
||||
import { Gtk } from "ags/gtk4";
|
||||
import { createPoll } from "ags/time";
|
||||
import AstalBattery from "gi://AstalBattery";
|
||||
import AstalNetwork from "gi://AstalNetwork";
|
||||
|
||||
export const SystemInfo = () => {
|
||||
const cpu = PollCMD("cat /sys/class/thermal/thermal_zone*/temp");
|
||||
const gpu = PollCMD("supergfxctl -g");
|
||||
const profile = PollCMD("asusctl profile -p");
|
||||
const tailscale = PollCMD("tailscale ping homelab");
|
||||
|
||||
const battery = AstalBattery.get_default();
|
||||
|
||||
const percentage = createBinding(battery, "percentage");
|
||||
const charging = createBinding(battery, "charging");
|
||||
const state = createBinding(battery, "state");
|
||||
const energyRate = createBinding(battery, "energyRate");
|
||||
|
||||
const chargingIcon = createComputed(
|
||||
[percentage, charging, state],
|
||||
(percentage, charging, state) => {
|
||||
const batFull = state === AstalBattery.State.FULLY_CHARGED;
|
||||
const p = percentage * 100;
|
||||
|
||||
if (batFull) return "fa-battery-full-symbolic";
|
||||
if (charging) return "fa-battery-charging-symbolic";
|
||||
if (p < 30) return "fa-battery-low-symbolic";
|
||||
return p < 70 ? "fa-battery-medium-symbolic" : "fa-battery-full-symbolic";
|
||||
},
|
||||
);
|
||||
|
||||
const network = AstalNetwork.get_default();
|
||||
const connnectivity = createBinding(network, "connectivity");
|
||||
|
||||
const getNetworkText = (
|
||||
conn: AstalNetwork.Connectivity,
|
||||
net: AstalNetwork.Network,
|
||||
) => {
|
||||
// no connection
|
||||
if (conn == 1) return "No connection";
|
||||
|
||||
// wired
|
||||
if (net.primary == 1) return "Wired";
|
||||
|
||||
// wifi
|
||||
const wifi = net.wifi;
|
||||
switch (wifi.internet) {
|
||||
case 0:
|
||||
return wifi.ssid;
|
||||
case 1:
|
||||
return "Connecting";
|
||||
case 2:
|
||||
return "Disconnected";
|
||||
}
|
||||
|
||||
return "NA";
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<box hexpand homogeneous spacing={20} cssClasses={["system-info"]}>
|
||||
<box
|
||||
cssClasses={["pill"]}
|
||||
spacing={15}
|
||||
orientation={Gtk.Orientation.VERTICAL}
|
||||
>
|
||||
<image iconName="fa-wifi-symbolic" />
|
||||
<label label={connnectivity((c) => getNetworkText(c, network))} />
|
||||
</box>
|
||||
|
||||
<box
|
||||
hexpand
|
||||
cssClasses={["pill"]}
|
||||
spacing={15}
|
||||
orientation={Gtk.Orientation.VERTICAL}
|
||||
>
|
||||
<image iconName="fa-video-card-symbolic" />
|
||||
<label label={gpu((val) => val)} />
|
||||
</box>
|
||||
|
||||
<box
|
||||
hexpand
|
||||
cssClasses={["pill"]}
|
||||
spacing={15}
|
||||
orientation={Gtk.Orientation.VERTICAL}
|
||||
>
|
||||
<image iconName="fa-speed-symbolic" />
|
||||
<label
|
||||
label={profile((val) => {
|
||||
const data = val.split(" ");
|
||||
return data[data.length - 1];
|
||||
})}
|
||||
/>
|
||||
</box>
|
||||
</box>
|
||||
|
||||
<box hexpand homogeneous spacing={20} cssClasses={["system-info"]}>
|
||||
<box
|
||||
hexpand
|
||||
cssClasses={["pill"]}
|
||||
spacing={15}
|
||||
orientation={Gtk.Orientation.VERTICAL}
|
||||
>
|
||||
<image iconName="fa-cpu-symbolic" />
|
||||
<label label={cpu((val) => `${parseInt(val) / 1000} °C`)} />
|
||||
</box>
|
||||
|
||||
<box
|
||||
cssClasses={["pill"]}
|
||||
spacing={15}
|
||||
orientation={Gtk.Orientation.VERTICAL}
|
||||
>
|
||||
<image iconName="fa-home-symbolic" />
|
||||
|
||||
<label
|
||||
label={tailscale((val) => {
|
||||
const data = val.split(" ");
|
||||
return data[data.length - 1];
|
||||
})}
|
||||
/>
|
||||
</box>
|
||||
|
||||
<box
|
||||
cssClasses={["pill"]}
|
||||
visible={createBinding(battery, "isPresent")}
|
||||
spacing={15}
|
||||
orientation={Gtk.Orientation.VERTICAL}
|
||||
>
|
||||
<image iconName={chargingIcon} />
|
||||
<box hexpand halign={Gtk.Align.CENTER} spacing={5}>
|
||||
<label label={percentage((p) => `${Math.floor(p * 100)}%`)} />
|
||||
<label label={energyRate((v) => `${Math.floor(v * 10) / 10}W`)} />
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const PollCMD = (cmd: string, ms: number = 5000) => {
|
||||
return createPoll("", ms, ["bash", "-c", cmd]);
|
||||
};
|
Reference in New Issue
Block a user