add(ags/bar): network section + tweak styles

This commit is contained in:
Franek 2025-05-18 20:09:31 +02:00
parent 1dbd2d1f0d
commit 5b073fa9d6
9 changed files with 127 additions and 12 deletions

View File

@ -60,4 +60,22 @@ export const skip = <T>(list: T[], items: number) => list.filter((_, i) => {
if (items > (list.length - 1)) items = list.length;
return i > (items - 1);
});
});
export const toHumanReadable = (bytes: number, unit: string, fractionDigits = 1) => {
const div = 1024;
if (Math.abs(bytes) < div) {
return bytes.toFixed(fractionDigits) + unit;
}
const units = ["ki", "Mi", "Gi", "Ti"];
let u = -1;
const r = 10 ** fractionDigits;
while (Math.round(Math.abs(bytes) * r) / r >= div && u < units.length) {
bytes /= div;
u++;
}
return bytes.toFixed(fractionDigits) + units[u] + unit;
}

View File

@ -0,0 +1,8 @@
import { Gio } from "astal";
export default function Separator() {
return <image
cssClasses={["separator"]}
gicon={Gio.Icon.new_for_string("switch-on-symbolic")}
/>
}

View File

@ -1,6 +1,11 @@
@use './theme_colors.scss' as *;
@use '_variables' as *;
@use 'mixins';
.material-icon {
@include mixins.material-icon;
}
.separator {
color: $base05;
}

View File

@ -2,7 +2,7 @@
window.bar {
font-weight: bold;
>box {
border-radius: 10px;
}
@ -11,10 +11,10 @@ window.bar {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
background: $base00;
padding: 0.25rem 1rem;
padding: 0rem 1rem;
margin: 0;
* { color: $base0B; }
*:not(.separator) { color: $base0B; }
}
.tray .item {

View File

@ -1,12 +1,13 @@
import { App, Astal, Gdk, Gtk } from "astal/gtk4"
import { Binding } from "astal"
import { App, Astal, Gdk, Gtk } from "astal/gtk4";
import Battery from "gi://AstalBattery";
import NetworkInfo from "./components/network_info";
import { BatteryInfo } from "./components/battery";
import Workspace from "./components/workspace";
import DateTime from "@lib/widgets/datetime";
import Workspace from "./workspace";
import TrayView from "./tray";
import TrayView from "./components/tray";
import Separator from "@/lib/widgets/separator";
export default function Bar(monitor_id: number) {
const { BOTTOM, LEFT, RIGHT } = Astal.WindowAnchor
@ -21,8 +22,8 @@ export default function Bar(monitor_id: number) {
return <window
visible
name={`bar_${monitor_id}`}
monitor={monitor_id}
name={`bar_${monitor_id}`}
monitor={monitor_id}
cssClasses={["bar"]}
exclusivity={Astal.Exclusivity.IGNORE}
anchor={BOTTOM | LEFT | RIGHT}
@ -38,8 +39,13 @@ export default function Bar(monitor_id: number) {
</menubutton>,
BatteryInfo({ battery }),
<button hasFrame={false} iconName={"applications-system-symbolic"} onButtonPressed={openQuickSettings} />,
NetworkInfo(),
TrayView()
]}
].reduce((acc, it) => <>
{acc}
{Separator()}
{it}
</>)}
</box>
</window>
}

View File

@ -0,0 +1,77 @@
import Network from "gi://AstalNetwork";
import { bind, Variable } from "astal";
import { toHumanReadable } from "@/lib/utils";
type IpOutput = Array<{
ifname: string;
stats64: {
rx: { bytes: number };
tx: { bytes: number };
};
}>;
type Usage = {
initialRx: number | null;
initialTx: number | null;
totalRx: number;
totalTx: number;
};
const getConnection = (instance?: Network.Wifi | Network.Wired) => {
if (!instance) return null;
const addresses = (instance instanceof Network.Wifi
? instance?.activeConnection
: instance?.connection)
?.ip4Config?.get_addresses();
return addresses.map(addr => addr.get_address()).join(", ");
}
export default function NetworkInfo() {
const net = Network.get_default();
const wiredConn = bind(net, "wired");
const wifiConn = bind(net, "wifi");
const currentConn = Variable.derive([
wiredConn,
wifiConn
], (wired, wifi) => {
switch (net.primary) {
case Network.Primary.WIFI: return wifi;
case Network.Primary.WIRED: return wired;
default: return;
}
})
const networkInterface = net.primary == 1 ? "enp0s31f6" : "wlp4s0";
const networkUsage = Variable<Usage>({
initialRx: null,
initialTx: null,
totalRx: 0,
totalTx: 0,
}).poll(
5000,
['ip', '-s', '-j', 'link', 'show', networkInterface],
(out, prev) => {
const ipOutput = JSON.parse(out) as IpOutput;
const totalRx = ipOutput?.reduce((prev, item) => prev + item.stats64.rx.bytes, 0);
const totalTx = ipOutput?.reduce((prev, item) => prev + item.stats64.tx.bytes, 0);
return {
initialRx: prev.initialRx ?? totalRx,
initialTx: prev.initialTx ?? totalTx,
totalTx,
totalRx,
};
}
);
const dataBinding = bind(networkUsage);
const binding = bind(currentConn);
return binding.as(Boolean) ? <box spacing={3}>
{binding.as(getConnection)}
TX: {dataBinding.as(data => toHumanReadable(data.totalTx / 4, "B/s"))}
RX: {dataBinding.as(data => toHumanReadable(data.totalRx / 4, "B/s"))}
</box> : <label>No network</label>
}

View File

@ -35,7 +35,8 @@ async function getClipboardHistory(history: Variable<Entry[]>) {
history.set(ids
.map((id, index) => ({ id, content: contents[index] }))
.filter(({ content }) => content && content.length > 0));
} catch {
} catch (rer){
console.error(rer)
history.set([]);
}
}