Converted a significant amount of files from js to ts.
This commit is contained in:
@@ -1,82 +0,0 @@
|
||||
const battery = await Service.import("battery");
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const { label: show_label } = options.bar.battery;
|
||||
|
||||
const BatteryLabel = () => {
|
||||
const isVis = Variable(battery.available);
|
||||
|
||||
const icon = () =>
|
||||
battery
|
||||
.bind("percent")
|
||||
.as((p) => `battery-level-${Math.floor(p / 10) * 10}-symbolic`);
|
||||
|
||||
battery.connect("changed", ({ available }) => {
|
||||
isVis.value = available;
|
||||
});
|
||||
|
||||
const formatTime = (seconds) => {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
return { hours, minutes };
|
||||
};
|
||||
|
||||
const generateTooltip = (timeSeconds, isCharging, isCharged) => {
|
||||
if (isCharged) {
|
||||
return "Fully Charged!!!";
|
||||
}
|
||||
|
||||
const { hours, minutes } = formatTime(timeSeconds);
|
||||
if (isCharging) {
|
||||
return `${hours} hours ${minutes} minutes until full`;
|
||||
} else {
|
||||
return `${hours} hours ${minutes} minutes left`;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "battery",
|
||||
visible: battery.bind("available"),
|
||||
tooltip_text: battery.bind("time_remaining").as((t) => t.toString()),
|
||||
children: Utils.merge(
|
||||
[battery.bind("available"), show_label.bind("value")],
|
||||
(batAvail, showLabel) => {
|
||||
if (batAvail && showLabel) {
|
||||
return [
|
||||
Widget.Icon({ icon: icon() }),
|
||||
Widget.Label({
|
||||
label: battery.bind("percent").as((p) => ` ${p}%`),
|
||||
}),
|
||||
];
|
||||
} else if (batAvail && !showLabel) {
|
||||
return [Widget.Icon({ icon: icon() })];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
),
|
||||
setup: (self) => {
|
||||
self.hook(battery, () => {
|
||||
if (battery.available) {
|
||||
self.tooltip_text = generateTooltip(
|
||||
battery.time_remaining,
|
||||
battery.charging,
|
||||
battery.charged,
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
isVis,
|
||||
boxClass: "battery",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "energymenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { BatteryLabel };
|
||||
84
modules/bar/battery/index.ts
Normal file
84
modules/bar/battery/index.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
const battery = await Service.import("battery");
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import EventHandler from 'types/widgets/button.ts'
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const { label: show_label } = options.bar.battery;
|
||||
|
||||
const BatteryLabel = () => {
|
||||
const isVis = Variable(battery.available);
|
||||
|
||||
const icon = () =>
|
||||
battery
|
||||
.bind("percent")
|
||||
.as((p) => `battery-level-${Math.floor(p / 10) * 10}-symbolic`);
|
||||
|
||||
battery.connect("changed", ({ available }) => {
|
||||
isVis.value = available;
|
||||
});
|
||||
|
||||
const formatTime = (seconds: number) => {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
return { hours, minutes };
|
||||
};
|
||||
|
||||
const generateTooltip = (timeSeconds: number, isCharging: boolean, isCharged: boolean) => {
|
||||
if (isCharged) {
|
||||
return "Fully Charged!!!";
|
||||
}
|
||||
|
||||
const { hours, minutes } = formatTime(timeSeconds);
|
||||
if (isCharging) {
|
||||
return `${hours} hours ${minutes} minutes until full`;
|
||||
} else {
|
||||
return `${hours} hours ${minutes} minutes left`;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "battery",
|
||||
visible: battery.bind("available"),
|
||||
tooltip_text: battery.bind("time_remaining").as((t) => t.toString()),
|
||||
children: Utils.merge(
|
||||
[battery.bind("available"), show_label.bind("value")],
|
||||
(batAvail, showLabel) => {
|
||||
if (batAvail && showLabel) {
|
||||
return [
|
||||
Widget.Icon({ icon: icon() }),
|
||||
Widget.Label({
|
||||
label: battery.bind("percent").as((p) => ` ${p}%`),
|
||||
}),
|
||||
];
|
||||
} else if (batAvail && !showLabel) {
|
||||
return [Widget.Icon({ icon: icon() })];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
),
|
||||
setup: (self) => {
|
||||
self.hook(battery, () => {
|
||||
if (battery.available) {
|
||||
self.tooltip_text = generateTooltip(
|
||||
battery.time_remaining,
|
||||
battery.charging,
|
||||
battery.charged,
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
isVis,
|
||||
boxClass: "battery",
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "energymenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { BatteryLabel };
|
||||
@@ -1,38 +0,0 @@
|
||||
const bluetooth = await Service.import('bluetooth')
|
||||
import options from "options";
|
||||
import { openMenu } from "../utils.js";
|
||||
|
||||
const Bluetooth = () => {
|
||||
const btIcon = Widget.Label({
|
||||
label: bluetooth.bind("enabled").as((v) => v ? "" : ""),
|
||||
class_name: "bar-bt_icon",
|
||||
});
|
||||
|
||||
const btText = Widget.Label({
|
||||
label: Utils.merge([bluetooth.bind("enabled"), options.bar.bluetooth.label.bind("value")], (btEnabled, showLabel) => {
|
||||
if (showLabel) {
|
||||
return btEnabled ? " On" : " Off"
|
||||
}
|
||||
return "";
|
||||
|
||||
}),
|
||||
class_name: "bar-bt_label",
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "volume",
|
||||
children: [btIcon, btText],
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "bluetooth",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "bluetoothmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export { Bluetooth }
|
||||
39
modules/bar/bluetooth/index.ts
Normal file
39
modules/bar/bluetooth/index.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
const bluetooth = await Service.import('bluetooth')
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import options from "options";
|
||||
import { openMenu } from "../utils.js";
|
||||
|
||||
const Bluetooth = () => {
|
||||
const btIcon = Widget.Label({
|
||||
label: bluetooth.bind("enabled").as((v) => v ? "" : ""),
|
||||
class_name: "bar-bt_icon",
|
||||
});
|
||||
|
||||
const btText = Widget.Label({
|
||||
label: Utils.merge([bluetooth.bind("enabled"), options.bar.bluetooth.label.bind("value")], (btEnabled, showLabel) => {
|
||||
if (showLabel) {
|
||||
return btEnabled ? " On" : " Off"
|
||||
}
|
||||
return "";
|
||||
|
||||
}),
|
||||
class_name: "bar-bt_label",
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "volume",
|
||||
children: [btIcon, btText],
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "bluetooth",
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "bluetoothmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export { Bluetooth }
|
||||
@@ -1,27 +0,0 @@
|
||||
import GLib from "gi://GLib";
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
const { format } = options.bar.clock;
|
||||
|
||||
const date = Variable(GLib.DateTime.new_now_local(), {
|
||||
poll: [1000, () => GLib.DateTime.new_now_local()],
|
||||
});
|
||||
const time = Utils.derive([date, format], (c, f) => c.format(f) || "");
|
||||
|
||||
const Clock = () => {
|
||||
return {
|
||||
component: Widget.Label({
|
||||
class_name: "clock",
|
||||
label: time.bind(),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "clock",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "calendarmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Clock };
|
||||
28
modules/bar/clock/index.ts
Normal file
28
modules/bar/clock/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import GLib from "gi://GLib";
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
const { format } = options.bar.clock;
|
||||
|
||||
const date = Variable(GLib.DateTime.new_now_local(), {
|
||||
poll: [1000, () => GLib.DateTime.new_now_local()],
|
||||
});
|
||||
const time = Utils.derive([date, format], (c, f) => c.format(f) || "");
|
||||
|
||||
const Clock = () => {
|
||||
return {
|
||||
component: Widget.Label({
|
||||
class_name: "clock",
|
||||
label: time.bind(),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "clock",
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "calendarmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Clock };
|
||||
@@ -1,101 +0,0 @@
|
||||
const mpris = await Service.import("mpris");
|
||||
import { openMenu } from "../utils.js";
|
||||
|
||||
const Media = () => {
|
||||
const activePlayer = Variable(mpris.players[0]);
|
||||
|
||||
mpris.connect("changed", (value) => {
|
||||
const statusOrder = {
|
||||
Playing: 1,
|
||||
Paused: 2,
|
||||
Stopped: 3,
|
||||
};
|
||||
|
||||
if (value.players.length === 0) {
|
||||
activePlayer.value = mpris.players[0];
|
||||
return;
|
||||
}
|
||||
|
||||
const isPlaying = value.players.find(
|
||||
(p) => p["play-back-status"] === "Playing",
|
||||
);
|
||||
|
||||
if (isPlaying) {
|
||||
activePlayer.value = value.players.sort(
|
||||
(a, b) =>
|
||||
statusOrder[a["play-back-status"]] -
|
||||
statusOrder[b["play-back-status"]],
|
||||
)[0];
|
||||
}
|
||||
});
|
||||
|
||||
const getIconForPlayer = (playerName) => {
|
||||
const windowTitleMap = [
|
||||
["Mozilla Firefox", " "],
|
||||
["Microsoft Edge", " "],
|
||||
["(.*)Discord(.*)", " "],
|
||||
["Plex", " "],
|
||||
["(.*) Spotify Free", " "],
|
||||
["(.*)Spotify Premium", " "],
|
||||
["Spotify", " "],
|
||||
["(.*)", " "],
|
||||
];
|
||||
|
||||
const foundMatch = windowTitleMap.find((wt) =>
|
||||
RegExp(wt[0]).test(playerName),
|
||||
);
|
||||
|
||||
return foundMatch ? foundMatch[1] : "";
|
||||
};
|
||||
|
||||
const songIcon = Variable("");
|
||||
|
||||
const label = Utils.watch(" Media ", mpris, "changed", () => {
|
||||
if (activePlayer.value) {
|
||||
const { track_title, identity } = activePlayer.value;
|
||||
songIcon.value = getIconForPlayer(identity);
|
||||
return track_title.length === 0
|
||||
? ` No media playing...`
|
||||
: ` ${track_title}`;
|
||||
} else {
|
||||
songIcon.value = "";
|
||||
return " Media ";
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
visible: false,
|
||||
child: Widget.Box({
|
||||
class_name: "media",
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "bar-media_icon",
|
||||
label: songIcon.bind("value"),
|
||||
maxWidthChars: 30,
|
||||
}),
|
||||
Widget.Label({
|
||||
label,
|
||||
truncate: "end",
|
||||
wrap: true,
|
||||
maxWidthChars: 30,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
isVisible: false,
|
||||
boxClass: "media",
|
||||
name: "media",
|
||||
props: {
|
||||
on_scroll_up: () => mpris.getPlayer("")?.next(),
|
||||
on_scroll_down: () => mpris.getPlayer("")?.previous(),
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "mediamenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Media };
|
||||
102
modules/bar/media/index.ts
Normal file
102
modules/bar/media/index.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const mpris = await Service.import("mpris");
|
||||
import { openMenu } from "../utils.js";
|
||||
|
||||
const Media = () => {
|
||||
const activePlayer = Variable(mpris.players[0]);
|
||||
|
||||
mpris.connect("changed", (value) => {
|
||||
const statusOrder = {
|
||||
Playing: 1,
|
||||
Paused: 2,
|
||||
Stopped: 3,
|
||||
};
|
||||
|
||||
if (value.players.length === 0) {
|
||||
activePlayer.value = mpris.players[0];
|
||||
return;
|
||||
}
|
||||
|
||||
const isPlaying = value.players.find(
|
||||
(p) => p["play-back-status"] === "Playing",
|
||||
);
|
||||
|
||||
if (isPlaying) {
|
||||
activePlayer.value = value.players.sort(
|
||||
(a, b) =>
|
||||
statusOrder[a["play-back-status"]] -
|
||||
statusOrder[b["play-back-status"]],
|
||||
)[0];
|
||||
}
|
||||
});
|
||||
|
||||
const getIconForPlayer = (playerName: string) => {
|
||||
const windowTitleMap = [
|
||||
["Mozilla Firefox", " "],
|
||||
["Microsoft Edge", " "],
|
||||
["(.*)Discord(.*)", " "],
|
||||
["Plex", " "],
|
||||
["(.*) Spotify Free", " "],
|
||||
["(.*)Spotify Premium", " "],
|
||||
["Spotify", " "],
|
||||
["(.*)", " "],
|
||||
];
|
||||
|
||||
const foundMatch = windowTitleMap.find((wt) =>
|
||||
RegExp(wt[0]).test(playerName),
|
||||
);
|
||||
|
||||
return foundMatch ? foundMatch[1] : "";
|
||||
};
|
||||
|
||||
const songIcon = Variable("");
|
||||
|
||||
const label = Utils.watch(" Media ", mpris, "changed", () => {
|
||||
if (activePlayer.value) {
|
||||
const { track_title, identity } = activePlayer.value;
|
||||
songIcon.value = getIconForPlayer(identity);
|
||||
return track_title.length === 0
|
||||
? ` No media playing...`
|
||||
: ` ${track_title}`;
|
||||
} else {
|
||||
songIcon.value = "";
|
||||
return " Media ";
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
visible: false,
|
||||
child: Widget.Box({
|
||||
class_name: "media",
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "bar-media_icon",
|
||||
label: songIcon.bind("value"),
|
||||
maxWidthChars: 30,
|
||||
}),
|
||||
Widget.Label({
|
||||
label,
|
||||
truncate: "end",
|
||||
wrap: true,
|
||||
maxWidthChars: 30,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
isVisible: false,
|
||||
boxClass: "media",
|
||||
name: "media",
|
||||
props: {
|
||||
on_scroll_up: () => mpris.getPlayer("")?.next(),
|
||||
on_scroll_down: () => mpris.getPlayer("")?.previous(),
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "mediamenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Media };
|
||||
@@ -1,22 +0,0 @@
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const Menu = () => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
child: Widget.Label({
|
||||
class_name: "bar-menu_label",
|
||||
label: options.bar.launcher.icon.bind("value"),
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "dashboard",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "dashboardmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Menu };
|
||||
23
modules/bar/menu/index.ts
Normal file
23
modules/bar/menu/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const Menu = () => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
child: Widget.Label({
|
||||
class_name: "bar-menu_label",
|
||||
label: options.bar.launcher.icon.bind("value"),
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "dashboard",
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "dashboardmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Menu };
|
||||
@@ -1,3 +1,4 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const network = await Service.import("network");
|
||||
import options from "options";
|
||||
import { openMenu } from "../utils.js";
|
||||
@@ -52,7 +53,7 @@ const Network = () => {
|
||||
isVisible: true,
|
||||
boxClass: "network",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "networkmenu");
|
||||
},
|
||||
},
|
||||
@@ -1,46 +0,0 @@
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const { show_total } = options.bar.notifications;
|
||||
|
||||
const notifs = await Service.import("notifications");
|
||||
|
||||
export const Notifications = () => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
hpack: "start",
|
||||
child: Widget.Box({
|
||||
hpack: "start",
|
||||
class_name: "bar-notifications",
|
||||
children: Utils.merge(
|
||||
[notifs.bind("notifications"), notifs.bind("dnd"), show_total.bind("value")],
|
||||
(notif, dnd, showTotal) => {
|
||||
const notifIcon = Widget.Label({
|
||||
hpack: "center",
|
||||
class_name: "bar-notifications-label",
|
||||
label: dnd ? "" : notif.length > 0 ? "" : "",
|
||||
});
|
||||
|
||||
const notifLabel = Widget.Label({
|
||||
hpack: "center",
|
||||
class_name: "bar-notifications-total",
|
||||
label: notif.length.toString(),
|
||||
});
|
||||
|
||||
if (showTotal) {
|
||||
return [notifIcon, notifLabel];
|
||||
}
|
||||
return [notifIcon];
|
||||
},
|
||||
),
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "notifications",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "notificationsmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
47
modules/bar/notifications/index.ts
Normal file
47
modules/bar/notifications/index.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
const { show_total } = options.bar.notifications;
|
||||
|
||||
const notifs = await Service.import("notifications");
|
||||
|
||||
export const Notifications = () => {
|
||||
return {
|
||||
component: Widget.Box({
|
||||
hpack: "start",
|
||||
child: Widget.Box({
|
||||
hpack: "start",
|
||||
class_name: "bar-notifications",
|
||||
children: Utils.merge(
|
||||
[notifs.bind("notifications"), notifs.bind("dnd"), show_total.bind("value")],
|
||||
(notif, dnd, showTotal) => {
|
||||
const notifIcon = Widget.Label({
|
||||
hpack: "center",
|
||||
class_name: "bar-notifications-label",
|
||||
label: dnd ? "" : notif.length > 0 ? "" : "",
|
||||
});
|
||||
|
||||
const notifLabel = Widget.Label({
|
||||
hpack: "center",
|
||||
class_name: "bar-notifications-total",
|
||||
label: notif.length.toString(),
|
||||
});
|
||||
|
||||
if (showTotal) {
|
||||
return [notifIcon, notifLabel];
|
||||
}
|
||||
return [notifIcon];
|
||||
},
|
||||
),
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "notifications",
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "notificationsmenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
const systemtray = await Service.import("systemtray");
|
||||
import { bash } from "lib/utils";
|
||||
import options from "options";
|
||||
|
||||
const { ignore } = options.bar.systray;
|
||||
|
||||
const SysTray = () => {
|
||||
const isVis = Variable(false);
|
||||
|
||||
const items = Utils.merge(
|
||||
[systemtray.bind("items"), ignore.bind("value")],
|
||||
(items, ignored) => {
|
||||
const filteredTray = items.filter(({ id }) => !ignored.includes(id));
|
||||
|
||||
isVis.value = filteredTray.length > 0;
|
||||
|
||||
return filteredTray.map((item) => {
|
||||
if (item.menu !== undefined) {
|
||||
item.menu["class_name"] = "systray-menu";
|
||||
}
|
||||
|
||||
return Widget.Button({
|
||||
cursor: "pointer",
|
||||
child: Widget.Icon({
|
||||
class_name: "systray-icon",
|
||||
icon: item.bind("icon"),
|
||||
}),
|
||||
on_primary_click: (_, event) => item.activate(event),
|
||||
on_secondary_click: (_, event) => item.openMenu(event),
|
||||
tooltip_markup: item.bind("tooltip_markup"),
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "systray",
|
||||
children: items,
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "systray",
|
||||
isVis,
|
||||
};
|
||||
};
|
||||
|
||||
export { SysTray };
|
||||
47
modules/bar/systray/index.ts
Normal file
47
modules/bar/systray/index.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const systemtray = await Service.import("systemtray");
|
||||
import options from "options";
|
||||
|
||||
const { ignore } = options.bar.systray;
|
||||
|
||||
const SysTray = () => {
|
||||
const isVis = Variable(false);
|
||||
|
||||
const items = Utils.merge(
|
||||
[systemtray.bind("items"), ignore.bind("value")],
|
||||
(items, ignored) => {
|
||||
const filteredTray = items.filter(({ id }) => !ignored.includes(id));
|
||||
|
||||
isVis.value = filteredTray.length > 0;
|
||||
|
||||
return filteredTray.map((item) => {
|
||||
if (item.menu !== undefined) {
|
||||
item.menu["class_name"] = "systray-menu";
|
||||
}
|
||||
|
||||
return Widget.Button({
|
||||
cursor: "pointer",
|
||||
child: Widget.Icon({
|
||||
class_name: "systray-icon",
|
||||
icon: item.bind("icon"),
|
||||
}),
|
||||
on_primary_click: (_: any, event: Gdk.Event) => item.activate(event),
|
||||
on_secondary_click: (_, event) => item.openMenu(event),
|
||||
tooltip_markup: item.bind("tooltip_markup"),
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
class_name: "systray",
|
||||
children: items,
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "systray",
|
||||
isVis,
|
||||
};
|
||||
};
|
||||
|
||||
export { SysTray };
|
||||
@@ -1,47 +0,0 @@
|
||||
export const closeAllMenus = () => {
|
||||
const menuWindows = App.windows
|
||||
.filter((w) => {
|
||||
if (w.name) {
|
||||
return /.*menu/.test(w.name);
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.map((w) => w.name);
|
||||
|
||||
menuWindows.forEach((w) => {
|
||||
if (w) {
|
||||
App.closeWindow(w);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const openMenu = (clicked, event, window) => {
|
||||
/*
|
||||
* NOTE: We have to make some adjustments so the menu pops up relatively
|
||||
* to the center of the button clicked. We don't want the menu to spawn
|
||||
* offcenter dependending on which edge of the button you click on.
|
||||
* -------------
|
||||
* To fix this, we take the x coordinate of the click within the button's bounds.
|
||||
* If you click the left edge of a 100 width button, then the x axis will be 0
|
||||
* and if you click the right edge then the x axis will be 100.
|
||||
* -------------
|
||||
* Then we divide the width of the button by 2 to get the center of the button and then get
|
||||
* the offset by subtracting the clicked x coordinate. Then we can apply that offset
|
||||
* to the x coordinate of the click relative to the screen to get the center of the
|
||||
* icon click.
|
||||
*/
|
||||
|
||||
const middleOfButton = Math.floor(clicked.get_allocated_width() / 2);
|
||||
const xAxisOfButtonClick = clicked.get_pointer()[0];
|
||||
const middleOffset = middleOfButton - xAxisOfButtonClick;
|
||||
|
||||
const clickPos = event.get_root_coords();
|
||||
const adjustedXCoord = clickPos[1] + middleOffset;
|
||||
const coords = [adjustedXCoord, clickPos[2]];
|
||||
|
||||
globalMousePos.value = coords;
|
||||
|
||||
closeAllMenus();
|
||||
App.toggleWindow(window);
|
||||
};
|
||||
51
modules/bar/utils.ts
Normal file
51
modules/bar/utils.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
|
||||
import { globalMousePos } from 'globals';
|
||||
|
||||
export const closeAllMenus = () => {
|
||||
const menuWindows = App.windows
|
||||
.filter((w) => {
|
||||
if (w.name) {
|
||||
return /.*menu/.test(w.name);
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.map((w) => w.name);
|
||||
|
||||
menuWindows.forEach((w) => {
|
||||
if (w) {
|
||||
App.closeWindow(w);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const openMenu = (clicked: any, event: Gdk.Event, window: string) => {
|
||||
/*
|
||||
* NOTE: We have to make some adjustments so the menu pops up relatively
|
||||
* to the center of the button clicked. We don't want the menu to spawn
|
||||
* offcenter dependending on which edge of the button you click on.
|
||||
* -------------
|
||||
* To fix this, we take the x coordinate of the click within the button's bounds.
|
||||
* If you click the left edge of a 100 width button, then the x axis will be 0
|
||||
* and if you click the right edge then the x axis will be 100.
|
||||
* -------------
|
||||
* Then we divide the width of the button by 2 to get the center of the button and then get
|
||||
* the offset by subtracting the clicked x coordinate. Then we can apply that offset
|
||||
* to the x coordinate of the click relative to the screen to get the center of the
|
||||
* icon click.
|
||||
*/
|
||||
|
||||
const middleOfButton = Math.floor(clicked.get_allocated_width() / 2);
|
||||
const xAxisOfButtonClick = clicked.get_pointer()[0];
|
||||
const middleOffset = middleOfButton - xAxisOfButtonClick;
|
||||
|
||||
const clickPos = event.get_root_coords();
|
||||
const adjustedXCoord = clickPos[1] + middleOffset;
|
||||
const coords = [adjustedXCoord, clickPos[2]];
|
||||
|
||||
globalMousePos.value = coords;
|
||||
|
||||
closeAllMenus();
|
||||
App.toggleWindow(window);
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
const audio = await Service.import("audio");
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
import { globalMousePos } from "globals.js";
|
||||
|
||||
const Volume = () => {
|
||||
const icons = {
|
||||
101: "",
|
||||
66: "",
|
||||
34: "",
|
||||
1: "",
|
||||
0: "",
|
||||
};
|
||||
|
||||
const getIcon = () => {
|
||||
const icon = Utils.merge(
|
||||
[audio.speaker.bind("is_muted"), audio.speaker.bind("volume")],
|
||||
(isMuted, vol) => {
|
||||
return isMuted
|
||||
? 0
|
||||
: [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100);
|
||||
},
|
||||
);
|
||||
|
||||
return icon.as((i) => icons[i]);
|
||||
};
|
||||
|
||||
const volIcn = Widget.Label({
|
||||
vpack: "center",
|
||||
label: getIcon(),
|
||||
class_name: "bar-volume_icon",
|
||||
});
|
||||
|
||||
const volPct = Widget.Label({
|
||||
vpack: "center",
|
||||
label: audio.speaker.bind("volume").as((v) => ` ${Math.floor(v * 100)}%`),
|
||||
class_name: "bar-volume_percentage",
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
vpack: "center",
|
||||
class_name: "volume",
|
||||
children: options.bar.volume.label.bind("value").as((showLabel) => {
|
||||
if (showLabel) {
|
||||
return [volIcn, volPct];
|
||||
}
|
||||
return [volIcn];
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "volume",
|
||||
props: {
|
||||
on_primary_click: (clicked, event) => {
|
||||
openMenu(clicked, event, "audiomenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Volume };
|
||||
63
modules/bar/volume/index.ts
Normal file
63
modules/bar/volume/index.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import Gdk from 'gi://Gdk?version=3.0';
|
||||
const audio = await Service.import("audio");
|
||||
import { openMenu } from "../utils.js";
|
||||
import options from "options";
|
||||
|
||||
import { globalMousePos } from "globals.js";
|
||||
|
||||
const Volume = () => {
|
||||
const icons = {
|
||||
101: "",
|
||||
66: "",
|
||||
34: "",
|
||||
1: "",
|
||||
0: "",
|
||||
};
|
||||
|
||||
const getIcon = () => {
|
||||
const icon = Utils.merge(
|
||||
[audio.speaker.bind("is_muted"), audio.speaker.bind("volume")],
|
||||
(isMuted, vol) => {
|
||||
return isMuted
|
||||
? 0
|
||||
: [101, 66, 34, 1, 0].find((threshold) => threshold <= vol * 100);
|
||||
},
|
||||
);
|
||||
|
||||
return icon.as((i) => i !== undefined ? icons[i] : 101);
|
||||
};
|
||||
|
||||
const volIcn = Widget.Label({
|
||||
vpack: "center",
|
||||
label: getIcon(),
|
||||
class_name: "bar-volume_icon",
|
||||
});
|
||||
|
||||
const volPct = Widget.Label({
|
||||
vpack: "center",
|
||||
label: audio.speaker.bind("volume").as((v) => ` ${Math.floor(v * 100)}%`),
|
||||
class_name: "bar-volume_percentage",
|
||||
});
|
||||
|
||||
return {
|
||||
component: Widget.Box({
|
||||
vpack: "center",
|
||||
class_name: "volume",
|
||||
children: options.bar.volume.label.bind("value").as((showLabel) => {
|
||||
if (showLabel) {
|
||||
return [volIcn, volPct];
|
||||
}
|
||||
return [volIcn];
|
||||
}),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "volume",
|
||||
props: {
|
||||
on_primary_click: (clicked: any, event: Gdk.Event) => {
|
||||
openMenu(clicked, event, "audiomenu");
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { Volume };
|
||||
@@ -1,36 +0,0 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
|
||||
const filterTitle = (windowtitle) => {
|
||||
const windowTitleMap = [
|
||||
["kitty", " Kitty Terminal"],
|
||||
["firefox", " Firefox"],
|
||||
["microsoft-edge", " Edge"],
|
||||
["discord", " Discord"],
|
||||
["org.kde.dolphin", " Dolphin"],
|
||||
["plex", " Plex"],
|
||||
["steam", " Steam"],
|
||||
["spotify", " Spotify"],
|
||||
["obsidian", " Obsidian"],
|
||||
["^$", " Desktop"],
|
||||
["(.+)", ` ${windowtitle.class.charAt(0).toUpperCase() + windowtitle.class.slice(1)}`],
|
||||
];
|
||||
|
||||
const foundMatch = windowTitleMap.find((wt) =>
|
||||
RegExp(wt[0]).test(windowtitle.class.toLowerCase()),
|
||||
);
|
||||
|
||||
return foundMatch ? foundMatch[1] : windowtitle.class;
|
||||
};
|
||||
|
||||
const ClientTitle = () => {
|
||||
return {
|
||||
component: Widget.Label({
|
||||
class_name: "window_title",
|
||||
label: hyprland.active.bind("client").as((v) => filterTitle(v)),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "windowtitle",
|
||||
};
|
||||
};
|
||||
|
||||
export { ClientTitle };
|
||||
37
modules/bar/window_title/index.ts
Normal file
37
modules/bar/window_title/index.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
import { ActiveClient } from 'types/service/hyprland'
|
||||
|
||||
const filterTitle = (windowtitle: ActiveClient) => {
|
||||
const windowTitleMap = [
|
||||
["kitty", " Kitty Terminal"],
|
||||
["firefox", " Firefox"],
|
||||
["microsoft-edge", " Edge"],
|
||||
["discord", " Discord"],
|
||||
["org.kde.dolphin", " Dolphin"],
|
||||
["plex", " Plex"],
|
||||
["steam", " Steam"],
|
||||
["spotify", " Spotify"],
|
||||
["obsidian", " Obsidian"],
|
||||
["^$", " Desktop"],
|
||||
["(.+)", ` ${windowtitle.class.charAt(0).toUpperCase() + windowtitle.class.slice(1)}`],
|
||||
];
|
||||
|
||||
const foundMatch = windowTitleMap.find((wt) =>
|
||||
RegExp(wt[0]).test(windowtitle.class.toLowerCase()),
|
||||
);
|
||||
|
||||
return foundMatch ? foundMatch[1] : windowtitle.class;
|
||||
};
|
||||
|
||||
const ClientTitle = () => {
|
||||
return {
|
||||
component: Widget.Label({
|
||||
class_name: "window_title",
|
||||
label: hyprland.active.bind("client").as((v) => filterTitle(v)),
|
||||
}),
|
||||
isVisible: true,
|
||||
boxClass: "windowtitle",
|
||||
};
|
||||
};
|
||||
|
||||
export { ClientTitle };
|
||||
@@ -1,14 +1,15 @@
|
||||
const hyprland = await Service.import("hyprland");
|
||||
import { WorkspaceRule, WorkspaceMap } from "lib/types/workspace";
|
||||
import options from "options";
|
||||
|
||||
const { workspaces, monitorSpecific } = options.bar.workspaces;
|
||||
|
||||
function range(length, start = 1) {
|
||||
function range(length: number, start = 1) {
|
||||
return Array.from({ length }, (_, i) => i + start);
|
||||
}
|
||||
|
||||
const Workspaces = (monitor = -1, ws = 8) => {
|
||||
const getWorkspacesForMonitor = (curWs, wsRules) => {
|
||||
const getWorkspacesForMonitor = (curWs: number, wsRules: WorkspaceMap) => {
|
||||
if (!wsRules || !Object.keys(wsRules).length) {
|
||||
return true;
|
||||
}
|
||||
@@ -20,13 +21,13 @@ const Workspaces = (monitor = -1, ws = 8) => {
|
||||
return wsRules[currentMonitorName].includes(curWs);
|
||||
};
|
||||
|
||||
const getWorkspaceRules = () => {
|
||||
const getWorkspaceRules = (): WorkspaceMap => {
|
||||
try {
|
||||
const rules = Utils.exec("hyprctl workspacerules -j");
|
||||
|
||||
const workspaceRules = {};
|
||||
|
||||
JSON.parse(rules).forEach((rule, index) => {
|
||||
JSON.parse(rules).forEach((rule: WorkspaceRule, index: number) => {
|
||||
if (Object.hasOwnProperty.call(workspaceRules, rule.monitor)) {
|
||||
workspaceRules[rule.monitor].push(index + 1);
|
||||
} else {
|
||||
@@ -37,6 +38,7 @@ const Workspaces = (monitor = -1, ws = 8) => {
|
||||
return workspaceRules;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user