From 11785d1a5db1d857141cc9c92e9b22e824dbab54 Mon Sep 17 00:00:00 2001 From: Jas Singh Date: Mon, 15 Jul 2024 01:37:41 -0700 Subject: [PATCH] Implemented config changing functionality --- README.md | 29 ++++--- config.js | 126 ++++++++++++++++++++--------- lib/session.ts | 4 +- main.ts | 40 +++++++++ modules/bar/Bar.ts | 107 +++++++++++++----------- modules/bar/notifications/index.js | 5 +- modules/bar/workspaces/index.js | 100 +++++++++++++++-------- modules/shared/barItemBox.js | 1 - options.ts | 37 +++------ tsconfig.json | 3 +- 10 files changed, 282 insertions(+), 170 deletions(-) create mode 100644 main.ts diff --git a/README.md b/README.md index 298f6e5..71563ed 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,15 @@ -Requirements: -``` -pipewire -bluez -bluez-utils -grimblast -gpu-screen-recorder -hyprpicker -btop -nmcli -networkmanager -dart-sass -brightnessctl -python -python-gpustat + +# Starter Config + +if suggestions don't work, first make sure +you have TypeScript LSP working in your editor + +if you do not want typechecking only suggestions + +```json +// tsconfig.json +"checkJs": false ``` + +types are symlinked to: +/usr/share/com.github.Aylur.ags/types diff --git a/config.js b/config.js index 81ae951..1daef44 100644 --- a/config.js +++ b/config.js @@ -1,46 +1,92 @@ -import { exec } from "resource:///com/github/Aylur/ags/utils.js"; -import { Bar, BarAlt } from "./modules/bar/index.js"; -import DirectoryMonitorService from "./directoryMonitorService.js"; -import MenuWindows from "./modules/menus/main.js"; -import Notifications from "./modules/notifications/index.js"; +import GLib from "gi://GLib" -const applyScss = () => { - // Compile scss - exec(`sass ${App.configDir}/scss/main.scss ${App.configDir}/style.css`); - exec( - `sass ${App.configDir}/scss/highlight.scss ${App.configDir}/highlight.css`, - ); - console.log("Scss compiled"); +const main = "/tmp/ags/hyprpanel/main.js" +const entry = `${App.configDir}/main.ts` +const bundler = GLib.getenv("AGS_BUNDLER") || "bun" - // Apply compiled css - App.resetCss(); - App.applyCss(`${App.configDir}/style.css`); - console.log("Compiled css applied"); -}; +const v = { + ags: pkg.version?.split(".").map(Number) || [], + expect: [1, 8, 1], +} -DirectoryMonitorService.connect("changed", () => applyScss()); +try { + switch (bundler) { + case "bun": await Utils.execAsync([ + "bun", "build", entry, + "--outfile", main, + "--external", "resource://*", + "--external", "gi://*", + "--external", "file://*", + ]); break -applyScss(); + case "esbuild": await Utils.execAsync([ + "esbuild", "--bundle", entry, + "--format=esm", + `--outfile=${main}`, + "--external:resource://*", + "--external:gi://*", + "--external:file://*", + ]); break -const workspaceMonitorMap = { - 0: [4, 5], - 1: [6, 7], - 2: [1, 2, 3, 8, 9, 10], -}; + default: + throw `"${bundler}" is not a valid bundler` + } -App.config({ - windows: [ - ...MenuWindows, - Notifications(), - BarAlt(0, workspaceMonitorMap), - BarAlt(1, workspaceMonitorMap), - Bar(2, workspaceMonitorMap), - ], - style: `${App.configDir}/style.css`, - closeWindowDelay: { - sideright: 350, - launcher: 350, - bar0: 350, - }, - onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`), -}); + if (v.ags[1] < v.expect[1] || v.ags[2] < v.expect[2]) { + print(`my config needs at least v${v.expect.join(".")}, yours is v${v.ags.join(".")}`) + App.quit() + } + + await import(`file://${main}`) +} catch (error) { + console.error(error) + App.quit() +} + +export { } +// import { exec } from "resource:///com/github/Aylur/ags/utils.js"; +// import { Bar, BarAlt } from "./modules/bar/index.js"; +// import DirectoryMonitorService from "./directoryMonitorService.js"; +// import MenuWindows from "./modules/menus/main.js"; +// import Notifications from "./modules/notifications/index.js"; +// +// const applyScss = () => { +// // Compile scss +// exec(`sass ${App.configDir}/scss/main.scss ${App.configDir}/style.css`); +// exec( +// `sass ${App.configDir}/scss/highlight.scss ${App.configDir}/highlight.css`, +// ); +// console.log("Scss compiled"); +// +// // Apply compiled css +// App.resetCss(); +// App.applyCss(`${App.configDir}/style.css`); +// console.log("Compiled css applied"); +// }; +// +// DirectoryMonitorService.connect("changed", () => applyScss()); +// +// applyScss(); +// +// const workspaceMonitorMap = { +// 0: [4, 5], +// 1: [6, 7], +// 2: [1, 2, 3, 8, 9, 10], +// }; +// +// App.config({ +// windows: [ +// ...MenuWindows, +// Notifications(), +// BarAlt(0, workspaceMonitorMap), +// BarAlt(1, workspaceMonitorMap), +// Bar(2, workspaceMonitorMap), +// ], +// style: `${App.configDir}/style.css`, +// closeWindowDelay: { +// sideright: 350, +// launcher: 350, +// bar0: 350, +// }, +// onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`), +// }); diff --git a/lib/session.ts b/lib/session.ts index 0e3e0cf..3c828c3 100644 --- a/lib/session.ts +++ b/lib/session.ts @@ -7,8 +7,8 @@ declare global { } Object.assign(globalThis, { - OPTIONS: `${GLib.get_user_cache_dir()}/ags/options.json`, - TMP: `${GLib.get_tmp_dir()}/asztal`, + OPTIONS: `${GLib.get_user_cache_dir()}/ags/hyprpanel/options.json`, + TMP: `${GLib.get_tmp_dir()}/ags/hyprpanel`, USER: GLib.get_user_name(), }) diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..061f8b6 --- /dev/null +++ b/main.ts @@ -0,0 +1,40 @@ +import { exec } from "resource:///com/github/Aylur/ags/utils.js"; +import DirectoryMonitorService from "./directoryMonitorService.js"; +import "lib/session" +import { Bar } from "modules/bar/Bar" +import MenuWindows from "./modules/menus/main.js"; +import Notifications from "./modules/notifications/index.js"; +import { forMonitors } from "lib/utils" + +const applyScss = () => { + // Compile scss + exec(`sass ${App.configDir}/scss/main.scss ${App.configDir}/style.css`); + exec( + `sass ${App.configDir}/scss/highlight.scss ${App.configDir}/highlight.css`, + ); + console.log("Scss compiled"); + + // Apply compiled css + App.resetCss(); + App.applyCss(`${App.configDir}/style.css`); + console.log("Compiled css applied"); +}; + +DirectoryMonitorService.connect("changed", () => applyScss()); + +applyScss(); + +App.config({ + onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`), + windows: [ + ...MenuWindows, + Notifications(), + ...forMonitors(Bar), + ], + style: `${App.configDir}/style.css`, + closeWindowDelay: { + sideright: 350, + launcher: 350, + bar0: 350, + }, +}) diff --git a/modules/bar/Bar.ts b/modules/bar/Bar.ts index a43bd67..52322dd 100644 --- a/modules/bar/Bar.ts +++ b/modules/bar/Bar.ts @@ -1,3 +1,4 @@ +const network = await Service.import("network"); import { Menu } from "./menu/index.js"; import { Workspaces } from "./workspaces/index.js"; import { ClientTitle } from "./window_title/index.js"; @@ -7,59 +8,75 @@ import { Volume } from "./volume/index.js"; import { Network } from "./network/index.js"; import { Bluetooth } from "./bluetooth/index.js"; import { BatteryLabel } from "./battery/index.js"; -import { Clock } from "./clock/index.js"; +import { Clock } from "./clock/index.js"; import { SysTray } from "./systray/index.js"; import { BarItemBox as WidgetContainer } from "../shared/barItemBox.js"; -import options from "options" +import options from "options"; -const { start, center, end } = options.bar.layout -const { transparent, position } = options.bar +const { start, center, end } = options.bar.layout; +const { transparent, position } = options.bar; -export type BarWidget = keyof typeof widget +export type BarWidget = keyof typeof widget; const widget = { - battery: WidgetContainer(BatteryLabel()), - dashboard: WidgetContainer(Menu()), - workspaces: WidgetContainer(Workspaces()), - windowtitle: WidgetContainer(ClientTitle()), - media: WidgetContainer(Media()), - notifications: WidgetContainer(Notifications()), - volume: WidgetContainer(Volume()), - network: WidgetContainer(Network()), - bluetooth: WidgetContainer(Bluetooth()), - clock: WidgetContainer(Clock()), - systray: WidgetContainer(SysTray()), - // expander: () => Widget.Box({ expand: true }), -} + battery: () => WidgetContainer(BatteryLabel()), + dashboard: () => WidgetContainer(Menu()), + workspaces: (monitor) => WidgetContainer(Workspaces(monitor, 10)), + windowtitle: () => WidgetContainer(ClientTitle()), + media: () => WidgetContainer(Media()), + notifications: () => WidgetContainer(Notifications()), + volume: () => WidgetContainer(Volume()), + network: () => WidgetContainer(Network()), + bluetooth: () => WidgetContainer(Bluetooth()), + clock: () => WidgetContainer(Clock()), + systray: () => WidgetContainer(SysTray()), + // expander: () => Widget.Box({ expand: true }), +}; -export const Bar = (monitor: number) => Widget.Window({ - monitor, +export const Bar = (monitor: number) => { + return Widget.Window({ + name: `bar-${monitor}`, class_name: "bar", - name: `bar${monitor}`, + monitor, + visible: true, + anchor: ["top", "left", "right"], exclusivity: "exclusive", - anchor: position.bind().as(pos => [pos, "right", "left"]), child: Widget.CenterBox({ - startWidget: Widget.Box({ - class_name: "box-left", - spacing: 5, - hexpand: true, - children: start.bind().as(s => s.map(w => widget[w])), - }), - centerWidget: Widget.Box({ - class_name: "box-center", - hpack: "center", - spacing: 5, - children: center.bind().as(c => c.map(w => widget[w])), - }), - endWidget: Widget.Box({ - class_name: "box-right", - hexpand: true, - spacing: 5, - children: end.bind().as(e => e.map(w => widget[w])), - }), - }), - setup: self => self.hook(transparent, () => { - self.toggleClassName("transparent", transparent.value) - }), -}) + visible: true, + startWidget: Widget.Box({ + class_name: "box-left", + spacing: 5, + hexpand: true, + setup: self => { + self.children = start.value.map(w => widget[w](monitor)); + self.hook(start, (self) => { + self.children = start.value.map(w => widget[w](monitor)); + }) + }, + }), + centerWidget: Widget.Box({ + class_name: "box-center", + hpack: "center", + spacing: 5, + setup: self => { + self.children = center.value.map(w => widget[w](monitor)); + self.hook(center, (self) => { + self.children = center.value.map(w => widget[w](monitor)); + }) + }, + }), + endWidget: Widget.Box({ + class_name: "box-right", + hpack: "end", + spacing: 5, + setup: self => { + self.children = end.value.map(w => widget[w](monitor)); + self.hook(end, (self) => { + self.children = end.value.map(w => widget[w](monitor)); + }) + }, + }), + }) + }); +}; diff --git a/modules/bar/notifications/index.js b/modules/bar/notifications/index.js index ac31e6a..989ca57 100644 --- a/modules/bar/notifications/index.js +++ b/modules/bar/notifications/index.js @@ -6,14 +6,11 @@ export const Notifications = () => { return { component: Widget.Box({ hpack: "start", - hexpand: true, - child: Widget.Button({ + child: Widget.Box({ hpack: "start", - hexpand: true, class_name: "bar-notifications", child: Widget.Label({ hpack: "center", - hexpand: true, class_name: "bar-notifications-label", setup: (self) => { self.hook(notifs, () => { diff --git a/modules/bar/workspaces/index.js b/modules/bar/workspaces/index.js index 83fc5ff..ef7c685 100644 --- a/modules/bar/workspaces/index.js +++ b/modules/bar/workspaces/index.js @@ -1,49 +1,81 @@ const hyprland = await Service.import("hyprland"); +import options from "options"; + +const { workspaces, monitorSpecific } = options.bar.workspaces; function range(length, start = 1) { return Array.from({ length }, (_, i) => i + start); } -const Workspaces = (monitor = -1, wsMap = {}, ws = 8) => { - const getWorkspacesForMonitor = (curWs) => { - if ( - Object.keys(wsMap) - .map((mn) => Number(mn)) - .includes(monitor) - ) { - return wsMap[monitor].includes(curWs); - } - return true; +const Workspaces = (monitor = -1, ws = 8) => { + const getWorkspacesForMonitor = (curWs, wsRules) => { + const monitorMap = {}; + hyprland.monitors.forEach((m) => (monitorMap[m.id] = m.name)); + + const currentMonitorName = monitorMap[monitor]; + return wsRules[currentMonitorName].includes(curWs); }; + + const getWorkspaceRules = () => { + try { + const rules = Utils.exec("hyprctl workspacerules -j"); + + const workspaceRules = {}; + + JSON.parse(rules).forEach((rule, index) => { + if (Object.hasOwnProperty.call(workspaceRules, rule.monitor)) { + workspaceRules[rule.monitor].push(index + 1); + } else { + workspaceRules[rule.monitor] = [index + 1]; + } + }); + + return workspaceRules; + } catch (err) { + console.error(err); + } + }; + return { component: Widget.Box({ class_name: "workspaces", - children: range(ws || 8) - .filter((i) => getWorkspacesForMonitor(i)) - .map((i) => { - return Widget.Label({ - attribute: i, - vpack: "center", - label: `${i}`, - setup: (self) => - self.hook(hyprland, () => { - self.toggleClassName( - "active", - hyprland.active.workspace.id === i, - ); - self.toggleClassName( - "occupied", - (hyprland.getWorkspace(i)?.windows || 0) > 0, - ); + children: Utils.merge( + [workspaces.bind(), monitorSpecific.bind()], + (workspaces, monitorSpecific) => { + return range(workspaces || 8) + .filter((i) => { + if (!monitorSpecific) { + return true; + } + const workspaceRules = getWorkspaceRules(); + return getWorkspacesForMonitor(i, workspaceRules); + }) + .map((i) => { + return Widget.Label({ + attribute: i, + vpack: "center", + label: `${i}`, + setup: (self) => + self.hook(hyprland, () => { + self.toggleClassName( + "active", + hyprland.active.workspace.id === i, + ); + self.toggleClassName( + "occupied", + (hyprland.getWorkspace(i)?.windows || 0) > 0, + ); - const isCurrentMonitor = - monitor !== -1 && - hyprland.getWorkspace(i)?.monitorID !== monitor; + const isCurrentMonitor = + monitor !== -1 && + hyprland.getWorkspace(i)?.monitorID !== monitor; - self.toggleClassName("hidden", isCurrentMonitor); - }), - }); - }), + self.toggleClassName("hidden", isCurrentMonitor); + }), + }); + }); + }, + ), setup: (box) => { if (ws === 0) { box.hook(hyprland.active.workspace, () => diff --git a/modules/shared/barItemBox.js b/modules/shared/barItemBox.js index 7330852..65901e8 100644 --- a/modules/shared/barItemBox.js +++ b/modules/shared/barItemBox.js @@ -3,7 +3,6 @@ export const BarItemBox = (child) => { if (Object.hasOwnProperty.call(child, "isVis")) { return child.isVis.bind("value"); } - return child.isVisible; }; diff --git a/options.ts b/options.ts index f19e493..11b14de 100644 --- a/options.ts +++ b/options.ts @@ -7,37 +7,17 @@ const options = mkOptions(OPTIONS, { autotheme: opt(false), theme: { - dark: { - primary: { - bg: opt("#51a4e7"), - fg: opt("#141414"), - }, - error: { - bg: opt("#e55f86"), - fg: opt("#141414"), - }, - bg: opt("#171717"), - fg: opt("#eeeeee"), - widget: opt("#eeeeee"), - border: opt("#eeeeee"), + primary: { + bg: opt("#51a4e7"), + fg: opt("#141414"), }, - light: { - primary: { - bg: opt("#426ede"), - fg: opt("#eeeeee"), - }, - error: { - bg: opt("#b13558"), - fg: opt("#eeeeee"), - }, - bg: opt("#fffffa"), - fg: opt("#080808"), - widget: opt("#080808"), - border: opt("#080808"), + error: { + bg: opt("#e55f86"), + fg: opt("#141414"), }, - + bg: opt("#171717"), + fg: opt("#eeeeee"), blur: opt(0), - scheme: opt<"dark" | "light">("dark"), widget: { opacity: opt(94) }, border: { width: opt(1), @@ -97,6 +77,7 @@ const options = mkOptions(OPTIONS, { }, workspaces: { workspaces: opt(7), + monitorSpecific: opt(true), }, taskbar: { iconSize: opt(0), diff --git a/tsconfig.json b/tsconfig.json index f03f2d1..9e03196 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "allowImportingTsExtensions": true, "target": "ES2022", "module": "ES2022", "lib": [ @@ -15,4 +16,4 @@ ], "skipLibCheck": true } -} \ No newline at end of file +}