[AGS] Prepare bar
This commit is contained in:
parent
196d553627
commit
a9c7b7d7ee
886
config/ags/bar/dump
Normal file
886
config/ags/bar/dump
Normal file
@ -0,0 +1,886 @@
|
|||||||
|
|
||||||
|
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 (
|
||||||
|
<window gdkmonitor={gdkmonitor}>
|
||||||
|
<box orientation="horizontal" spacing={10}>
|
||||||
|
<box>
|
||||||
|
<label>{dateTime}</label>
|
||||||
|
<label>{`CPU: ${cpu}%`}</label>
|
||||||
|
<label>{`Mem: ${memory}%`}</label>
|
||||||
|
<label>{`Brightness: ${brightness}%`}</label>
|
||||||
|
<label>{`Battery: ${battery}%`}</label>
|
||||||
|
<label>{`Workspace: ${workspaceNumber}`}</label>
|
||||||
|
</box>
|
||||||
|
<label>{windowTitle}</label>
|
||||||
|
<box>
|
||||||
|
<tray />
|
||||||
|
<button icon="quickaction" menu={quickActionMenu} />
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
</window>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<window gdkmonitor={gdkmonitor}>
|
||||||
|
<box orientation="horizontal" spacing={10}>
|
||||||
|
<box>
|
||||||
|
<label>{dateTime}</label>
|
||||||
|
<label>{`CPU: ${cpu}%`}</label>
|
||||||
|
<label>{`Mem: ${memory}%`}</label>
|
||||||
|
<label>{`Brightness: ${brightness}%`}</label>
|
||||||
|
<label>{`Battery: ${battery}%`}</label>
|
||||||
|
<label>{`Workspace: ${workspaceNumber}`}</label>
|
||||||
|
</box>
|
||||||
|
<label>{windowTitle}</label>
|
||||||
|
<box>
|
||||||
|
<tray />
|
||||||
|
<button icon="quickaction" menu={quickActionMenu} />
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
</window>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = (
|
||||||
|
<menu>
|
||||||
|
<item label="📶 WiFi" onActivate={toggleWiFi} />
|
||||||
|
<item label="→ Pick Network" onActivate={pickWiFi} />
|
||||||
|
|
||||||
|
<item label="🔵 Bluetooth" onActivate={toggleBluetooth} />
|
||||||
|
<item label="→ Pick Device" onActivate={pickBluetooth} />
|
||||||
|
|
||||||
|
<item label="🔊 Volume" onActivate={adjustVolume} />
|
||||||
|
<item label="🎙️ Microphone" onActivate={adjustMic} />
|
||||||
|
<item label="🔌 Power" onActivate={showPowerMenu} />
|
||||||
|
</menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<menu>
|
||||||
|
<item label="📶 WiFi" onActivate={toggleWiFi} />
|
||||||
|
{wifiPicker}
|
||||||
|
|
||||||
|
<item label="🔵 Bluetooth" onActivate={toggleBluetooth} />
|
||||||
|
{btPicker}
|
||||||
|
|
||||||
|
<item label="🔊 Volume" onActivate={adjustVolume} />
|
||||||
|
<item label="🎙️ Microphone" onActivate={adjustMic} />
|
||||||
|
<item label="🔌 Power" onActivate={showPowerMenu} />
|
||||||
|
</menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<box className="toggle-row" orientation="horizontal">
|
||||||
|
<button className={active ? "toggle active" : "toggle"} onClicked={onToggle}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
<button className="arrow" onClicked={onExpand}>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<menu className="quickactions-menu">
|
||||||
|
|
||||||
|
<submenu label="">
|
||||||
|
{createToggleRow({
|
||||||
|
label: "📶 WiFi",
|
||||||
|
active: wifi.get_state() !== AstalNetwork.WifiState.DISCONNECTED,
|
||||||
|
onToggle: () => {
|
||||||
|
wifi.get_state() === AstalNetwork.WifiState.DISCONNECTED ? wifi.connect() : wifi.disconnect();
|
||||||
|
},
|
||||||
|
onExpand: () => {
|
||||||
|
refreshWifiMenu();
|
||||||
|
wifiSub.popup();
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</submenu>
|
||||||
|
|
||||||
|
<submenu label="">
|
||||||
|
{createToggleRow({
|
||||||
|
label: "🔵 Bluetooth",
|
||||||
|
active: bt.get_powered(),
|
||||||
|
onToggle: () => bt.set_powered(!bt.get_powered()),
|
||||||
|
onExpand: () => {
|
||||||
|
refreshBtMenu();
|
||||||
|
btSub.popup();
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</submenu>
|
||||||
|
|
||||||
|
<item label="🔊 Volume" onActivate={() => exec("pavucontrol")} />
|
||||||
|
<item label="🎙️ Microphone" onActivate={() => exec("pavucontrol")} />
|
||||||
|
<item label="🔌 Power" onActivate={() => exec("power-menu")} />
|
||||||
|
</menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<box className="toggle-row" orientation="horizontal">
|
||||||
|
<button className={active ? "toggle active" : "toggle"} onClicked={onToggle}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
<button className="arrow" onClicked={onExpand}>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPowerRow({ onExpand }) {
|
||||||
|
return (
|
||||||
|
<box className="toggle-row" orientation="horizontal">
|
||||||
|
<button className="toggle" onClicked={() => exec("systemctl suspend")}>
|
||||||
|
🔋 Power
|
||||||
|
</button>
|
||||||
|
<button className="arrow" onClicked={onExpand}>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<menu className="quickactions-menu">
|
||||||
|
|
||||||
|
{/* WiFi */}
|
||||||
|
<submenu label="">
|
||||||
|
{createToggleRow({
|
||||||
|
label: "📶 WiFi",
|
||||||
|
active: wifi.get_state() !== AstalNetwork.WifiState.DISCONNECTED,
|
||||||
|
onToggle: () =>
|
||||||
|
wifi.get_state() === AstalNetwork.WifiState.DISCONNECTED
|
||||||
|
? wifi.connect()
|
||||||
|
: wifi.disconnect(),
|
||||||
|
onExpand: () => {
|
||||||
|
refreshWifiMenu();
|
||||||
|
wifiSub.popup();
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</submenu>
|
||||||
|
|
||||||
|
{/* Bluetooth */}
|
||||||
|
<submenu label="">
|
||||||
|
{createToggleRow({
|
||||||
|
label: "🔵 Bluetooth",
|
||||||
|
active: bt.get_powered(),
|
||||||
|
onToggle: () => bt.set_powered(!bt.get_powered()),
|
||||||
|
onExpand: () => {
|
||||||
|
refreshBtMenu();
|
||||||
|
btSub.popup();
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</submenu>
|
||||||
|
|
||||||
|
{/* Output Volume */}
|
||||||
|
<box className="audio-control">
|
||||||
|
<label>🔊 Output</label>
|
||||||
|
<scale
|
||||||
|
value={audio.get_output_volume()}
|
||||||
|
onChange={v => audio.set_output_volume(v)}
|
||||||
|
drawValue={false}
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
/>
|
||||||
|
<button onClicked={() => {
|
||||||
|
refreshOutputDevices();
|
||||||
|
outputSub.popup();
|
||||||
|
}}>⋯</button>
|
||||||
|
</box>
|
||||||
|
|
||||||
|
{/* Input Volume */}
|
||||||
|
<box className="audio-control">
|
||||||
|
<label>🎙️ Mic</label>
|
||||||
|
<scale
|
||||||
|
value={audio.get_input_volume()}
|
||||||
|
onChange={v => audio.set_input_volume(v)}
|
||||||
|
drawValue={false}
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
/>
|
||||||
|
<button onClicked={() => {
|
||||||
|
refreshInputDevices();
|
||||||
|
inputSub.popup();
|
||||||
|
}}>⋯</button>
|
||||||
|
</box>
|
||||||
|
|
||||||
|
{/* Media Controls */}
|
||||||
|
{media && (
|
||||||
|
<box className="media-control">
|
||||||
|
<label>{media.get_artist()} – {media.get_title()}</label>
|
||||||
|
<box>
|
||||||
|
<button onClicked={() => media.prev()}>⏮</button>
|
||||||
|
<button onClicked={() => media.play_pause()}>⏯</button>
|
||||||
|
<button onClicked={() => media.next()}>⏭</button>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Power */}
|
||||||
|
<submenu label="">
|
||||||
|
{createPowerRow({
|
||||||
|
onExpand: () => {
|
||||||
|
refreshPowerMenu();
|
||||||
|
powerSub.popup();
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
</submenu>
|
||||||
|
</menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { createQuickActionsMenu };
|
@ -9,6 +9,6 @@
|
|||||||
// "checkJs": true,
|
// "checkJs": true,
|
||||||
// "allowJs": true,
|
// "allowJs": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "astal/gtk4",
|
"jsxImportSource": "astal/gtk3",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,23 @@
|
|||||||
import { App, Astal, Gtk, Gdk } from "astal/gtk4"
|
import { createQuickActionsMenu } from "./QuickActions";
|
||||||
import { Variable } from "astal"
|
import { GLib } from "astal";
|
||||||
|
import { Astal, Gdk, Gtk } from "astal/gtk3";
|
||||||
|
|
||||||
const time = Variable("").poll(1000, "date")
|
const Bar = (gdkmonitor: Gdk.Monitor) => {
|
||||||
|
|
||||||
export default function Bar(gdkmonitor: Gdk.Monitor) {
|
return (
|
||||||
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
|
<window gdkmonitor={gdkmonitor}
|
||||||
|
cssClasses={["Bar"]}>
|
||||||
return <window
|
<box orientation={Gtk.Orientation.HORIZONTAL} spacing={10}>
|
||||||
visible
|
<box>
|
||||||
cssClasses={["Bar"]}
|
</box>
|
||||||
gdkmonitor={gdkmonitor}
|
<label>{windowTitle}</label>
|
||||||
exclusivity={Astal.Exclusivity.EXCLUSIVE}
|
<box>
|
||||||
anchor={TOP | LEFT | RIGHT}
|
<tray />
|
||||||
application={App}>
|
<button icon="quickaction" menu={quickActionMenu} />
|
||||||
<centerbox cssName="centerbox">
|
</box>
|
||||||
<button
|
</box>
|
||||||
onClicked="echo hello"
|
|
||||||
hexpand
|
|
||||||
halign={Gtk.Align.CENTER}
|
|
||||||
>
|
|
||||||
Welcome to AGS!
|
|
||||||
</button>
|
|
||||||
<box />
|
|
||||||
<menubutton
|
|
||||||
hexpand
|
|
||||||
halign={Gtk.Align.CENTER}
|
|
||||||
>
|
|
||||||
<label label={time()} />
|
|
||||||
<popover>
|
|
||||||
<Gtk.Calendar />
|
|
||||||
</popover>
|
|
||||||
</menubutton>
|
|
||||||
</centerbox>
|
|
||||||
</window>
|
</window>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Bar;
|
||||||
|
76
config/ags/bar/ui/QuickActions.tsx
Normal file
76
config/ags/bar/ui/QuickActions.tsx
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
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 = (
|
||||||
|
<menu>
|
||||||
|
<item label="📶 WiFi" onActivate={toggleWiFi} />
|
||||||
|
<item label="→ Pick Network" onActivate={pickWiFi} />
|
||||||
|
|
||||||
|
<item label="🔵 Bluetooth" onActivate={toggleBluetooth} />
|
||||||
|
<item label="→ Pick Device" onActivate={pickBluetooth} />
|
||||||
|
|
||||||
|
<item label="🔊 Volume" onActivate={adjustVolume} />
|
||||||
|
<item label="🎙️ Microphone" onActivate={adjustMic} />
|
||||||
|
<item label="🔌 Power" onActivate={showPowerMenu} />
|
||||||
|
</menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
return quickActionsMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the function
|
||||||
|
export { createQuickActionsMenu };
|
57
config/ags/bar/ui/modules/Hyprland.tsx
Normal file
57
config/ags/bar/ui/modules/Hyprland.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import AstalTray from "gi://AstalTray";
|
||||||
|
import { bind } from "astal";
|
||||||
|
import AstalHyprland from "gi://AstalHyprland";
|
||||||
|
|
||||||
|
const SysTray = () => {
|
||||||
|
const tray = AstalTray.get_default();
|
||||||
|
|
||||||
|
return <box className="SysTray">
|
||||||
|
{bind(tray, "items").as( items => items.map( item => (
|
||||||
|
<button
|
||||||
|
tooltipMarkup={bind(item, "tooltipMarkup")}
|
||||||
|
usePopover={false}
|
||||||
|
actionGroup={bind(item, "actionGroup").as(ag => ["dbusmenu", ag])}
|
||||||
|
menuModel={bind(item, "menuModel")}>
|
||||||
|
<icon gicon={bind(item, "gicon")} />
|
||||||
|
</button>
|
||||||
|
) ) ) }
|
||||||
|
</box>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const HyprlandWorkspace = () => {
|
||||||
|
const hypr = AstalHyprland.get_default()
|
||||||
|
|
||||||
|
return <box className={"HyprlandWorkspaces"}>
|
||||||
|
{bind(hypr, "workspaces").as(wss => wss
|
||||||
|
.filter(ws => !(ws.id >= -99 && ws.id <= -2)) // filter out special workspaces
|
||||||
|
.sort((a, b) => a.id - b.id)
|
||||||
|
.map(ws => (
|
||||||
|
<button
|
||||||
|
className={bind(hypr, "focusedWorkspace").as(fw =>
|
||||||
|
ws === fw ? "HyprlandFocusedWorkspace" : "")}
|
||||||
|
onClicked={() => ws.focus()}>
|
||||||
|
{ws.id}
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</box>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const HyprlandActiveWindow = () => {
|
||||||
|
const hypr = AstalHyprland.get_default();
|
||||||
|
const focused = bind( hypr, "focusedClient" );
|
||||||
|
|
||||||
|
return <box className={"HyprlandFocusedClients"} visible={focused.as(Boolean)}>
|
||||||
|
{focused.as( client => (
|
||||||
|
client && <label label={bind( client, "title" ).as( String )} />
|
||||||
|
))}
|
||||||
|
</box>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
HyprlandWorkspace,
|
||||||
|
HyprlandActiveWindow,
|
||||||
|
SysTray
|
||||||
|
}
|
37
config/ags/bar/ui/quickactions.scss
Normal file
37
config/ags/bar/ui/quickactions.scss
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
68
config/ags/bar/util/hyprland.ts
Normal file
68
config/ags/bar/util/hyprland.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import AstalHyprland from "gi://AstalHyprland";
|
||||||
|
|
||||||
|
const getAvailableWorkspaces = (): number[] => {
|
||||||
|
const workspaces: number[] = [];
|
||||||
|
AstalHyprland.get_default().get_workspaces().forEach( val => {
|
||||||
|
workspaces.push( val.get_id() );
|
||||||
|
} )
|
||||||
|
return workspaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCurrentWorkspaceID = (): number => {
|
||||||
|
return AstalHyprland.get_default().get_focused_workspace().get_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCurrentWindowTitle = (): string => {
|
||||||
|
return AstalHyprland.get_default().get_focused_client().get_title();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the workspace ID of a window by its address
|
||||||
|
* @param address - The address of the window
|
||||||
|
* @returns The workspace ID
|
||||||
|
*/
|
||||||
|
const getWorkspaceIDOfWindowByAddress = ( address: string ): number => {
|
||||||
|
AstalHyprland.get_default().get_clients().forEach( client => {
|
||||||
|
if ( client.get_address() === address ) {
|
||||||
|
return client.get_workspace().get_id();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface HyprlandSubscriptions {
|
||||||
|
[key: string]: ( data: string ) => void;
|
||||||
|
}
|
||||||
|
const hooks: HyprlandSubscriptions = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event listener for Hyprland events.
|
||||||
|
* @param event - A hyprland IPC event. See https://wiki.hyprland.org/IPC/. Useful events include: urgent, windowtitlev2, workspace, createworkspacev2, destroyworkspacev2, activewindowv2
|
||||||
|
* @param cb - The callback function
|
||||||
|
*/
|
||||||
|
const subscribeToUpdates = ( event: string, cb: ( data: string ) => void ): void => {
|
||||||
|
hooks[ event ] = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to events. Must be called at some point if events are to be listened for
|
||||||
|
*/
|
||||||
|
const listen = () => {
|
||||||
|
AstalHyprland.get_default().connect( "event", ( name: string, data: string ) => {
|
||||||
|
if ( hooks[ name ] ) {
|
||||||
|
hooks[ name ]( data );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getAvailableWorkspaces,
|
||||||
|
getCurrentWorkspaceID,
|
||||||
|
getCurrentWindowTitle,
|
||||||
|
getWorkspaceIDOfWindowByAddress,
|
||||||
|
subscribeToUpdates,
|
||||||
|
listen
|
||||||
|
}
|
2
config/ags/quickactions/.gitignore
vendored
2
config/ags/quickactions/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
@girs/
|
|
@ -1,10 +0,0 @@
|
|||||||
import { App } from "astal/gtk4"
|
|
||||||
import style from "./style.scss"
|
|
||||||
import Bar from "./widget/Bar"
|
|
||||||
|
|
||||||
App.start({
|
|
||||||
css: style,
|
|
||||||
main() {
|
|
||||||
App.get_monitors().map(Bar)
|
|
||||||
},
|
|
||||||
})
|
|
21
config/ags/quickactions/env.d.ts
vendored
21
config/ags/quickactions/env.d.ts
vendored
@ -1,21 +0,0 @@
|
|||||||
declare const SRC: string
|
|
||||||
|
|
||||||
declare module "inline:*" {
|
|
||||||
const content: string
|
|
||||||
export default content
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "*.scss" {
|
|
||||||
const content: string
|
|
||||||
export default content
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "*.blp" {
|
|
||||||
const content: string
|
|
||||||
export default content
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "*.css" {
|
|
||||||
const content: string
|
|
||||||
export default content
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "astal-shell",
|
|
||||||
"dependencies": {
|
|
||||||
"astal": "/usr/share/astal/gjs"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
|
|
||||||
$fg-color: #{"@theme_fg_color"};
|
|
||||||
$bg-color: #{"@theme_bg_color"};
|
|
||||||
|
|
||||||
window.Bar {
|
|
||||||
background: transparent;
|
|
||||||
color: $fg-color;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
>centerbox {
|
|
||||||
background: $bg-color;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
|
||||||
"compilerOptions": {
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"strict": true,
|
|
||||||
"target": "ES2022",
|
|
||||||
"module": "ES2022",
|
|
||||||
"moduleResolution": "Bundler",
|
|
||||||
// "checkJs": true,
|
|
||||||
// "allowJs": true,
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"jsxImportSource": "astal/gtk4",
|
|
||||||
}
|
|
||||||
}
|
|
27
prompts.md
Normal file
27
prompts.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Bar
|
||||||
|
## Attempt 1
|
||||||
|
Use Astal (https://aylur.github.io/astal) to write me a new status bar for hyprland. You may use JSX (be aware, it's not react, but gjs based and has therefore some limitations), but I prefer using the other syntax that is similar to what it was for AGS (the old version of astal), which more closely resembles GTK syntax. The bar should include the following, from left to right:
|
||||||
|
Left aligned
|
||||||
|
- Date & Time (with seconds, preferably)
|
||||||
|
- System stats (i.e. CPU, Memory util, Screen Brightness & Battery status, if available)
|
||||||
|
- Workspace number
|
||||||
|
Centered
|
||||||
|
- The window name
|
||||||
|
Right aligned (still left to right)
|
||||||
|
- System tray
|
||||||
|
- QuickAction menu in GNOME QuickAction menu style, but only the closed version showing icons for volume, mic, WiFi / Ethernet and a Power icon. For the icons (all throughout the bar) use the fluentui-icons (so the Windows 11 icons). If you can't provide them here, tell me what icon should go there and I will put it there manually
|
||||||
|
|
||||||
|
The actual QuickAction Menu (which you could also write in a separate file) will provide options where I can pick WiFi, Bluetooth (also turn it on and off), change volume of mic and output, pick the mic and output, have media controls and have a power menu).
|
||||||
|
|
||||||
|
For the QuickAction menu, provide a function that is exposed from the file to open and close it, as for all the features (like enabling BT, WiFi, etc).
|
||||||
|
|
||||||
|
|
||||||
|
### Followups
|
||||||
|
To the WiFi and Bluetooth menus, add the option to pick a WiFi Network / Bluetooth device. Please also fully extract the QuickActions menu to a separate file.
|
||||||
|
|
||||||
|
|
||||||
|
Now, can you also provide scss for the bar, such that:
|
||||||
|
- I have an easy way to customize colours (which I will be doing using one of my scripts, so having a separate colour config file will be a great option)
|
||||||
|
- it is very rounded (the corners)
|
||||||
|
- it has a very sleek, but modern design, with only a single accent colour
|
||||||
|
- Hovering over something clickable uses a hover colour
|
Loading…
x
Reference in New Issue
Block a user