import GLib from "gi://GLib";
import Astal from "gi://Astal";
import AstalHyprland from "gi://AstalHyprland";
import Gio from "gi://Gio";
import Gtk from "gi://Gtk";
import Gdk from "gi://Gdk";
import { exec } from "gi://GLib";
function getSystemStats() {
const cpu = exec("sh -c 'top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk \"{print 100 - $1}\"'");
const memory = exec("free | grep Mem | awk '{print $3/$2 * 100.0}'");
const brightness = exec("brightnessctl g");
const battery = exec("cat /sys/class/power_supply/BAT0/capacity");
return { cpu, memory, brightness, battery };
}
function getWorkspaceNumber() {
return AstalHyprland.get_default().get_active_workspace().get_id();
}
function getWindowTitle() {
return exec("xdotool getactivewindow getwindowname");
}
function getDateTime() {
return GLib.DateTime.new_now_local().format("%a %b %d, %Y %H:%M:%S");
}
function createQuickActionMenu() {
const menu = new Gtk.Menu();
const volumeItem = new Gtk.MenuItem({ label: "🔊 Volume" });
const micItem = new Gtk.MenuItem({ label: "🎙️ Microphone" });
const wifiItem = new Gtk.MenuItem({ label: "📶 WiFi" });
const powerItem = new Gtk.MenuItem({ label: "🔌 Power" });
menu.append(volumeItem);
menu.append(micItem);
menu.append(wifiItem);
menu.append(powerItem);
volumeItem.show();
micItem.show();
wifiItem.show();
powerItem.show();
return menu;
}
function Bar(gdkmonitor) {
const { cpu, memory, brightness, battery } = getSystemStats();
const workspaceNumber = getWorkspaceNumber();
const windowTitle = getWindowTitle();
const dateTime = getDateTime();
const quickActionMenu = createQuickActionMenu();
return (
);
}
function main() {
for (const m of AstalHyprland.get_default().get_monitors()) {
Bar(m.gdk_monitor);
}
}
App.start({ main });
import GLib from "gi://GLib";
import Astal from "gi://Astal";
import AstalHyprland from "gi://AstalHyprland";
import Gtk from "gi://Gtk";
import { exec } from "gi://GLib";
import { createQuickActionsMenu } from "./quickactions.js";
function getSystemStats() {
const cpu = exec("sh -c 'top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk \"{print 100 - $1}\"'");
const memory = exec("free | grep Mem | awk '{print $3/$2 * 100.0}'");
const brightness = exec("brightnessctl g");
const battery = exec("cat /sys/class/power_supply/BAT0/capacity");
return { cpu, memory, brightness, battery };
}
function getWorkspaceNumber() {
return AstalHyprland.get_default().get_active_workspace().get_id();
}
function getWindowTitle() {
return exec("xdotool getactivewindow getwindowname");
}
function getDateTime() {
return GLib.DateTime.new_now_local().format("%a %b %d, %Y %H:%M:%S");
}
function Bar(gdkmonitor) {
const { cpu, memory, brightness, battery } = getSystemStats();
const workspaceNumber = getWorkspaceNumber();
const windowTitle = getWindowTitle();
const dateTime = getDateTime();
const quickActionMenu = createQuickActionsMenu();
return (
);
}
function main() {
for (const m of AstalHyprland.get_default().get_monitors()) {
Bar(m.gdk_monitor);
}
}
App.start({ main });
import AstalNetwork from "gi://AstalNetwork";
import AstalBluetooth from "gi://AstalBluetooth";
import Gtk from "gi://Gtk";
function createQuickActionsMenu() {
const menu = new Gtk.Menu();
const wifiItem = new Gtk.MenuItem({ label: "📶 WiFi" });
const bluetoothItem = new Gtk.MenuItem({ label: "🔵 Bluetooth" });
const volumeItem = new Gtk.MenuItem({ label: "🔊 Volume" });
const micItem = new Gtk.MenuItem({ label: "🎙️ Microphone" });
const powerItem = new Gtk.MenuItem({ label: "🔌 Power" });
menu.append(wifiItem);
menu.append(bluetoothItem);
menu.append(volumeItem);
menu.append(micItem);
menu.append(powerItem);
wifiItem.connect("activate", () => toggleWiFi());
bluetoothItem.connect("activate", () => toggleBluetooth());
volumeItem.connect("activate", () => adjustVolume());
micItem.connect("activate", () => adjustMic());
powerItem.connect("activate", () => showPowerMenu());
wifiItem.show();
bluetoothItem.show();
volumeItem.show();
micItem.show();
powerItem.show();
return menu;
}
function toggleWiFi() {
const network = AstalNetwork.get_default();
const wifi = network.get_wifi();
const state = wifi.get_state();
if (state === AstalNetwork.WifiState.DISCONNECTED) {
wifi.connect();
} else {
wifi.disconnect();
}
}
function toggleBluetooth() {
const bluetooth = AstalBluetooth.get_default();
const adapter = bluetooth.get_adapter();
const powered = adapter.get_powered();
adapter.set_powered(!powered);
}
function adjustVolume() {
exec("pavucontrol");
}
function adjustMic() {
exec("pavucontrol");
}
function showPowerMenu() {
exec("power-menu");
}
export { createQuickActionsMenu };
// colors.scss
$accent: #4a90e2; // Primary accent color (change this)
$bg: #1e1e2e; // Background
$fg: #f8f8f2; // Foreground/text
$hover: lighten($accent, 10%);
$border: rgba(255, 255, 255, 0.1);
@import "colors";
* {
all: unset;
font-family: "JetBrainsMono Nerd Font", monospace;
font-size: 14px;
color: $fg;
}
window {
background-color: transparent;
}
box {
background-color: $bg;
border-radius: 16px;
padding: 6px 12px;
border: 1px solid $border;
margin: 8px;
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.3);
}
label {
padding: 0 8px;
}
// Clickable buttons/icons (e.g. QuickAction, tray items)
button {
background-color: transparent;
border-radius: 12px;
padding: 6px;
transition: background-color 0.2s ease-in-out;
&:hover {
background-color: $hover;
}
}
// System Tray area
tray {
padding: 0 8px;
}
// Layout specifics
.left-section,
.center-section,
.right-section {
padding: 0 12px;
}
.left-section {
border-right: 1px solid $border;
}
.right-section {
border-left: 1px solid $border;
}
// Icons (you'll replace them with fluentui icons)
.icon {
font-family: "FluentUI System Icons"; // Ensure this font is loaded
font-size: 16px;
}
import Gtk from "gi://Gtk";
import AstalNetwork from "gi://AstalNetwork";
import AstalBluetooth from "gi://AstalBluetooth";
import { exec } from "gi://GLib";
let quickActionsMenu;
// Toggle WiFi connection
function toggleWiFi() {
const network = AstalNetwork.get_default();
const wifi = network.get_wifi();
const state = wifi.get_state();
if (state === AstalNetwork.WifiState.DISCONNECTED) {
wifi.connect();
} else {
wifi.disconnect();
}
}
// Toggle Bluetooth power state
function toggleBluetooth() {
const bluetooth = AstalBluetooth.get_default();
const adapter = bluetooth.get_adapter();
const powered = adapter.get_powered();
adapter.set_powered(!powered);
}
// Adjust volume or microphone (opens pavucontrol)
function adjustVolume() {
exec("pavucontrol");
}
function adjustMic() {
exec("pavucontrol");
}
// Power menu
function showPowerMenu() {
exec("power-menu");
}
// Show WiFi network picker
function pickWiFi() {
const wifi = AstalNetwork.get_default().get_wifi();
wifi.show_picker();
}
// Show Bluetooth device picker
function pickBluetooth() {
const bluetooth = AstalBluetooth.get_default();
bluetooth.show_picker();
}
// Create menu using JSX
function createQuickActionsMenu() {
quickActionsMenu = (
);
return quickActionsMenu;
}
// Export the function
export { createQuickActionsMenu };
import Gtk from "gi://Gtk";
import AstalNetwork from "gi://AstalNetwork";
import AstalBluetooth from "gi://AstalBluetooth";
import { exec } from "gi://GLib";
function toggleWiFi() {
const network = AstalNetwork.get_default();
const wifi = network.get_wifi();
wifi.get_state() === AstalNetwork.WifiState.DISCONNECTED
? wifi.connect()
: wifi.disconnect();
}
function toggleBluetooth() {
const adapter = AstalBluetooth.get_default().get_adapter();
adapter.set_powered(!adapter.get_powered());
}
function adjustVolume() {
exec("pavucontrol");
}
function adjustMic() {
exec("pavucontrol");
}
function showPowerMenu() {
exec("power-menu");
}
// Build submenu for WiFi networks
function buildWifiMenu() {
const wifi = AstalNetwork.get_default().get_wifi();
const menu = new Gtk.Menu();
for (const ap of wifi.get_access_points()) {
const ssid = ap.get_ssid();
const strength = ap.get_strength();
const item = new Gtk.MenuItem({ label: `${ssid} (${strength}%)` });
item.connect("activate", () => {
wifi.connect_access_point(ap);
});
item.show();
menu.append(item);
}
return menu;
}
// Build submenu for Bluetooth devices
function buildBluetoothMenu() {
const bluetooth = AstalBluetooth.get_default();
const menu = new Gtk.Menu();
for (const device of bluetooth.get_devices()) {
const name = device.get_name();
const connected = device.get_connected();
const label = connected ? `✔ ${name}` : name;
const item = new Gtk.MenuItem({ label });
item.connect("activate", () => {
if (!connected) {
device.connect_device();
} else {
device.disconnect_device();
}
});
item.show();
menu.append(item);
}
return menu;
}
function createQuickActionsMenu() {
const wifiPicker = new Gtk.MenuItem({ label: "→ Pick Network ▸" });
const btPicker = new Gtk.MenuItem({ label: "→ Pick Device ▸" });
const wifiSubMenu = new Gtk.Menu();
const btSubMenu = new Gtk.Menu();
// Populate submenus on open
wifiPicker.connect("activate", () => {
wifiSubMenu.foreach(child => wifiSubMenu.remove(child));
const newMenu = buildWifiMenu();
newMenu.foreach(child => wifiSubMenu.append(child));
wifiSubMenu.show_all();
});
btPicker.connect("activate", () => {
btSubMenu.foreach(child => btSubMenu.remove(child));
const newMenu = buildBluetoothMenu();
newMenu.foreach(child => btSubMenu.append(child));
btSubMenu.show_all();
});
wifiPicker.set_submenu(wifiSubMenu);
btPicker.set_submenu(btSubMenu);
return (
);
}
export { createQuickActionsMenu };
import Gtk from "gi://Gtk";
import AstalNetwork from "gi://AstalNetwork";
import AstalBluetooth from "gi://AstalBluetooth";
import { exec } from "gi://GLib";
function createToggleRow({ label, active, onToggle, onExpand }) {
return (
);
}
function createQuickActionsMenu() {
const wifi = AstalNetwork.get_default().get_wifi();
const bt = AstalBluetooth.get_default().get_adapter();
const wifiSub = new Gtk.Menu();
const btSub = new Gtk.Menu();
function refreshWifiMenu() {
wifiSub.foreach(c => wifiSub.remove(c));
for (const ap of wifi.get_access_points()) {
const item = new Gtk.MenuItem({ label: `${ap.get_ssid()} (${ap.get_strength()}%)` });
item.connect("activate", () => wifi.connect_access_point(ap));
item.show();
wifiSub.append(item);
}
}
function refreshBtMenu() {
btSub.foreach(c => btSub.remove(c));
for (const dev of AstalBluetooth.get_default().get_devices()) {
const name = dev.get_name();
const label = dev.get_connected() ? `✔ ${name}` : name;
const item = new Gtk.MenuItem({ label });
item.connect("activate", () => {
dev.get_connected() ? dev.disconnect_device() : dev.connect_device();
});
item.show();
btSub.append(item);
}
}
return (
);
}
export { createQuickActionsMenu };
@import "colors";
.toggle-row {
background-color: $bg;
border-radius: 12px;
margin: 6px 0;
overflow: hidden;
border: 1px solid $border;
button {
padding: 10px 16px;
font-size: 14px;
transition: background 0.2s ease;
border: none;
background: transparent;
&:hover {
background-color: $hover;
}
}
.toggle {
flex: 1;
background-color: transparent;
text-align: left;
&.active {
background-color: $accent;
color: white;
}
}
.arrow {
width: 40px;
background-color: transparent;
text-align: center;
}
}
.audio-control {
display: flex;
align-items: center;
padding: 8px 12px;
gap: 8px;
label {
min-width: 60px;
color: $fg;
}
scale {
flex: 1;
}
button {
background-color: transparent;
padding: 6px;
border-radius: 6px;
&:hover {
background-color: $hover;
}
}
}
.media-control {
padding: 12px;
text-align: center;
label {
display: block;
margin-bottom: 6px;
}
button {
margin: 0 4px;
padding: 6px 10px;
border-radius: 6px;
&:hover {
background-color: $hover;
}
}
}
import Gtk from "gi://Gtk";
import AstalNetwork from "gi://AstalNetwork";
import AstalBluetooth from "gi://AstalBluetooth";
import AstalAudio from "gi://AstalAudio";
import AstalMedia from "gi://AstalMedia";
import { exec } from "gi://GLib";
// Helpers
function createToggleRow({ label, active, onToggle, onExpand }) {
return (
);
}
function createPowerRow({ onExpand }) {
return (
);
}
function createQuickActionsMenu() {
const wifi = AstalNetwork.get_default().get_wifi();
const bt = AstalBluetooth.get_default().get_adapter();
const audio = AstalAudio.get_default();
const media = AstalMedia.get_default();
// Submenus
const wifiSub = new Gtk.Menu();
const btSub = new Gtk.Menu();
const powerSub = new Gtk.Menu();
const outputSub = new Gtk.Menu();
const inputSub = new Gtk.Menu();
function refreshWifiMenu() {
wifiSub.foreach(c => wifiSub.remove(c));
for (const ap of wifi.get_access_points()) {
const item = new Gtk.MenuItem({ label: `${ap.get_ssid()} (${ap.get_strength()}%)` });
item.connect("activate", () => wifi.connect_access_point(ap));
item.show();
wifiSub.append(item);
}
}
function refreshBtMenu() {
btSub.foreach(c => btSub.remove(c));
for (const dev of AstalBluetooth.get_default().get_devices()) {
const label = dev.get_connected() ? `✔ ${dev.get_name()}` : dev.get_name();
const item = new Gtk.MenuItem({ label });
item.connect("activate", () =>
dev.get_connected() ? dev.disconnect_device() : dev.connect_device()
);
item.show();
btSub.append(item);
}
}
function refreshPowerMenu() {
const entries = [
{ label: "⏻ Shutdown", cmd: "systemctl poweroff" },
{ label: "🔁 Reboot", cmd: "systemctl reboot" },
{ label: "🔒 Lock", cmd: "loginctl lock-session" },
{ label: "🚪 Logout", cmd: "hyprctl dispatch exit" },
];
powerSub.foreach(c => powerSub.remove(c));
for (const entry of entries) {
const item = new Gtk.MenuItem({ label: entry.label });
item.connect("activate", () => exec(entry.cmd));
item.show();
powerSub.append(item);
}
}
function refreshOutputDevices() {
outputSub.foreach(c => outputSub.remove(c));
for (const device of audio.get_outputs()) {
const label = device.is_default() ? `✔ ${device.get_description()}` : device.get_description();
const item = new Gtk.MenuItem({ label });
item.connect("activate", () => audio.set_default_output(device));
item.show();
outputSub.append(item);
}
}
function refreshInputDevices() {
inputSub.foreach(c => inputSub.remove(c));
for (const device of audio.get_inputs()) {
const label = device.is_default() ? `✔ ${device.get_description()}` : device.get_description();
const item = new Gtk.MenuItem({ label });
item.connect("activate", () => audio.set_default_input(device));
item.show();
inputSub.append(item);
}
}
return (
);
}
export { createQuickActionsMenu };