From a9c19bd2e1ddefb3845d224cfb6cd03e7a52a2cd Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Wed, 26 Jun 2024 00:10:21 +0545 Subject: [PATCH] update ags --- config/ags/README.md | 15 + config/ags/apps/settings/bluetooth.ts | 12 + config/ags/apps/settings/main.ts | 129 +++ config/ags/apps/settings/network.ts | 214 ++++ config/ags/apps/window.ts | 3 + config/ags/assets/mixer-symbolic.svg | 6 - config/ags/colors.css | 46 + config/ags/colors.json | 116 --- config/ags/config.js | 21 +- config/ags/config.json | 51 - config/ags/functions/globals.js | 19 - config/ags/functions/hyprland/init.js | 7 - .../functions/hyprland/window_animation.js | 13 - config/ags/functions/hyprland/window_blur.js | 14 - config/ags/functions/monitor_configuration.js | 127 --- config/ags/functions/theme/ags.js | 135 --- config/ags/functions/theme/gtk.js | 46 - config/ags/functions/theme/hyprland.js | 34 - config/ags/functions/theme/init.js | 42 - config/ags/functions/theme/matugen.js | 10 - config/ags/functions/utils.js | 159 --- config/ags/functions/wallpaper.js | 33 - config/ags/init.js | 16 - config/ags/main.ts | 82 ++ config/ags/modules/applauncher.ts | 179 ++++ config/ags/modules/bar.ts | 451 +++++++++ config/ags/modules/cliphist.ts | 127 +++ config/ags/modules/media.ts | 172 ++++ config/ags/modules/misc/Dock.js | 114 +++ .../ags/modules/misc/cairo_roundedcorner.js | 51 + config/ags/modules/misc/clickthrough.js | 4 + config/ags/modules/misc/popupwindow.ts | 44 + config/ags/modules/notificationPopups.ts | 257 +++++ config/ags/modules/sidebar/buttons.ts | 178 ++++ config/ags/modules/sidebar/main.ts | 16 + config/ags/modules/sidebar/management.ts | 387 +++++++ config/ags/modules/sidebar/navigation.ts | 88 ++ .../ags/modules/sidebar/notifications-old.ts | 183 ++++ config/ags/modules/sidebar/notifications.ts | 76 ++ config/ags/modules/sidebar/sidebar.ts | 18 + config/ags/modules/sidebar/system.ts | 210 ++++ config/ags/scripts/backlight.sh | 88 ++ config/ags/scripts/bluetooth.sh | 47 + config/ags/scripts/brightness.sh | 51 + config/ags/scripts/cliphist.sh | 21 + config/ags/scripts/network.sh | 29 + config/ags/scripts/night-light.sh | 134 +++ config/ags/scripts/system.sh | 48 + config/ags/scripts/wayland-idle-inhibitor.py | 83 ++ config/ags/services/brightness.js | 71 -- config/ags/services/configuration.js | 79 -- config/ags/services/network_speed.js | 108 -- config/ags/services/powermenu.js | 54 - config/ags/services/screen_record.js | 94 -- config/ags/style-apps.css | 157 +++ config/ags/style.css | 942 ++++++++++++++++++ config/ags/style/colors.scss | 48 - config/ags/style/common.scss | 338 ------- config/ags/style/functions.scss | 13 - config/ags/style/main.scss | 20 - config/ags/style/vars.scss | 19 - config/ags/style/widgets/applauncher.scss | 5 - config/ags/style/widgets/audio-popup.scss | 58 -- config/ags/style/widgets/bar.scss | 21 - config/ags/style/widgets/battery-popup.scss | 52 - config/ags/style/widgets/control-center.scss | 90 -- config/ags/style/widgets/datemenu.scss | 27 - config/ags/style/widgets/media.scss | 46 - config/ags/style/widgets/network-popup.scss | 4 - config/ags/style/widgets/network-speed.scss | 17 - config/ags/style/widgets/notifications.scss | 85 -- config/ags/style/widgets/osd.scss | 36 - config/ags/style/widgets/overview.scss | 139 --- config/ags/style/widgets/powermenu.scss | 74 -- config/ags/style/widgets/system-monitor.scss | 89 -- config/ags/style/widgets/systray.scss | 6 - config/ags/style/widgets/tray.scss | 11 - .../ags/style/widgets/wallpaper-picker.scss | 127 --- config/ags/style/widgets/workspaces.scss | 60 -- .../svg/New Folder/brightness-onPrimary.svg | 5 + config/ags/svg/New Folder/dark-onPrimary.svg | 16 + config/ags/svg/brightness-onPrimary.svg | 5 + config/ags/svg/dark-onPrimary.svg | 12 + config/ags/tsconfig.json | 22 + config/ags/types | 1 + config/ags/vars.js | 200 ---- config/ags/widget/FileChooserDialog.js | 3 - config/ags/widget/PanelButton.js | 27 - config/ags/widget/PopupWindow.js | 141 --- config/ags/widget/ToggleButton.js | 128 --- config/ags/widget/applauncher/PanelButton.js | 28 - config/ags/widget/applauncher/Window.js | 99 -- config/ags/widget/audio/PanelButton.js | 34 - config/ags/widget/audio/Window.js | 190 ---- config/ags/widget/bar/Window.js | 129 --- config/ags/widget/battery/PanelButton.js | 32 - config/ags/widget/battery/Window.js | 146 --- config/ags/widget/client/PanelButton.js | 46 - .../ags/widget/control_center/Brightness.js | 18 - config/ags/widget/control_center/Media.js | 153 --- .../widget/control_center/Notifications.js | 109 -- .../ags/widget/control_center/PanelButton.js | 25 - config/ags/widget/control_center/Window.js | 50 - .../control_center/buttons/Container.js | 28 - .../control_center/buttons/color_picker.js | 28 - .../control_center/buttons/dark_mode.js | 16 - .../ags/widget/control_center/buttons/dnd.js | 16 - .../control_center/buttons/mic_access.js | 22 - .../control_center/buttons/power_menu.js | 13 - .../control_center/buttons/qs_button.js | 23 - .../control_center/buttons/screen_record.js | 22 - .../control_center/buttons/screenshot.js | 44 - .../control_center/buttons/wallpaper.js | 13 - config/ags/widget/datemenu/PanelButton.js | 28 - config/ags/widget/datemenu/Window.js | 41 - config/ags/widget/hyprsplash/Window.js | 21 - config/ags/widget/network/Bluetooth.js | 63 -- config/ags/widget/network/PanelButton.js | 31 - config/ags/widget/network/Wifi.js | 56 -- config/ags/widget/network/Window.js | 35 - .../ags/widget/network_speed/PanelButton.js | 37 - .../ags/widget/notifications/PopupWindow.js | 100 -- .../ags/widget/notifications/notifications.js | 139 --- config/ags/widget/osd/Progress.js | 63 -- config/ags/widget/osd/ProgressOsd.js | 83 -- config/ags/widget/osd/RegularOsd.js | 99 -- .../ags/widget/powermenu/PowerMenuWindow.js | 48 - .../widget/powermenu/VerificationWindow.js | 54 - .../ags/widget/screen_record/PanelButton.js | 32 - config/ags/widget/system_monitor/Window.js | 126 --- config/ags/widget/tray/tray.js | 16 - config/ags/widget/wallpaper_picker/Window.js | 187 ---- config/ags/widget/workspaces/PanelButton.js | 102 -- config/ags/windows.js | 44 - 134 files changed, 4732 insertions(+), 5813 deletions(-) create mode 100644 config/ags/README.md create mode 100644 config/ags/apps/settings/bluetooth.ts create mode 100644 config/ags/apps/settings/main.ts create mode 100644 config/ags/apps/settings/network.ts create mode 100644 config/ags/apps/window.ts delete mode 100644 config/ags/assets/mixer-symbolic.svg create mode 100644 config/ags/colors.css delete mode 100644 config/ags/colors.json delete mode 100644 config/ags/config.json delete mode 100644 config/ags/functions/globals.js delete mode 100644 config/ags/functions/hyprland/init.js delete mode 100644 config/ags/functions/hyprland/window_animation.js delete mode 100644 config/ags/functions/hyprland/window_blur.js delete mode 100644 config/ags/functions/monitor_configuration.js delete mode 100644 config/ags/functions/theme/ags.js delete mode 100644 config/ags/functions/theme/gtk.js delete mode 100644 config/ags/functions/theme/hyprland.js delete mode 100644 config/ags/functions/theme/init.js delete mode 100644 config/ags/functions/theme/matugen.js delete mode 100644 config/ags/functions/utils.js delete mode 100644 config/ags/functions/wallpaper.js delete mode 100644 config/ags/init.js create mode 100644 config/ags/main.ts create mode 100644 config/ags/modules/applauncher.ts create mode 100644 config/ags/modules/bar.ts create mode 100644 config/ags/modules/cliphist.ts create mode 100644 config/ags/modules/media.ts create mode 100644 config/ags/modules/misc/Dock.js create mode 100644 config/ags/modules/misc/cairo_roundedcorner.js create mode 100644 config/ags/modules/misc/clickthrough.js create mode 100644 config/ags/modules/misc/popupwindow.ts create mode 100644 config/ags/modules/notificationPopups.ts create mode 100644 config/ags/modules/sidebar/buttons.ts create mode 100644 config/ags/modules/sidebar/main.ts create mode 100644 config/ags/modules/sidebar/management.ts create mode 100644 config/ags/modules/sidebar/navigation.ts create mode 100644 config/ags/modules/sidebar/notifications-old.ts create mode 100644 config/ags/modules/sidebar/notifications.ts create mode 100644 config/ags/modules/sidebar/sidebar.ts create mode 100644 config/ags/modules/sidebar/system.ts create mode 100755 config/ags/scripts/backlight.sh create mode 100755 config/ags/scripts/bluetooth.sh create mode 100755 config/ags/scripts/brightness.sh create mode 100755 config/ags/scripts/cliphist.sh create mode 100755 config/ags/scripts/network.sh create mode 100755 config/ags/scripts/night-light.sh create mode 100755 config/ags/scripts/system.sh create mode 100755 config/ags/scripts/wayland-idle-inhibitor.py delete mode 100644 config/ags/services/brightness.js delete mode 100644 config/ags/services/configuration.js delete mode 100644 config/ags/services/network_speed.js delete mode 100644 config/ags/services/powermenu.js delete mode 100644 config/ags/services/screen_record.js create mode 100644 config/ags/style-apps.css create mode 100644 config/ags/style.css delete mode 100644 config/ags/style/colors.scss delete mode 100644 config/ags/style/common.scss delete mode 100644 config/ags/style/functions.scss delete mode 100644 config/ags/style/main.scss delete mode 100644 config/ags/style/vars.scss delete mode 100644 config/ags/style/widgets/applauncher.scss delete mode 100644 config/ags/style/widgets/audio-popup.scss delete mode 100644 config/ags/style/widgets/bar.scss delete mode 100644 config/ags/style/widgets/battery-popup.scss delete mode 100644 config/ags/style/widgets/control-center.scss delete mode 100644 config/ags/style/widgets/datemenu.scss delete mode 100644 config/ags/style/widgets/media.scss delete mode 100644 config/ags/style/widgets/network-popup.scss delete mode 100644 config/ags/style/widgets/network-speed.scss delete mode 100644 config/ags/style/widgets/notifications.scss delete mode 100644 config/ags/style/widgets/osd.scss delete mode 100644 config/ags/style/widgets/overview.scss delete mode 100644 config/ags/style/widgets/powermenu.scss delete mode 100644 config/ags/style/widgets/system-monitor.scss delete mode 100644 config/ags/style/widgets/systray.scss delete mode 100644 config/ags/style/widgets/tray.scss delete mode 100644 config/ags/style/widgets/wallpaper-picker.scss delete mode 100644 config/ags/style/widgets/workspaces.scss create mode 100644 config/ags/svg/New Folder/brightness-onPrimary.svg create mode 100644 config/ags/svg/New Folder/dark-onPrimary.svg create mode 100644 config/ags/svg/brightness-onPrimary.svg create mode 100644 config/ags/svg/dark-onPrimary.svg create mode 100644 config/ags/tsconfig.json create mode 120000 config/ags/types delete mode 100644 config/ags/vars.js delete mode 100644 config/ags/widget/FileChooserDialog.js delete mode 100644 config/ags/widget/PanelButton.js delete mode 100644 config/ags/widget/PopupWindow.js delete mode 100644 config/ags/widget/ToggleButton.js delete mode 100644 config/ags/widget/applauncher/PanelButton.js delete mode 100644 config/ags/widget/applauncher/Window.js delete mode 100644 config/ags/widget/audio/PanelButton.js delete mode 100644 config/ags/widget/audio/Window.js delete mode 100644 config/ags/widget/bar/Window.js delete mode 100644 config/ags/widget/battery/PanelButton.js delete mode 100644 config/ags/widget/battery/Window.js delete mode 100644 config/ags/widget/client/PanelButton.js delete mode 100644 config/ags/widget/control_center/Brightness.js delete mode 100644 config/ags/widget/control_center/Media.js delete mode 100644 config/ags/widget/control_center/Notifications.js delete mode 100644 config/ags/widget/control_center/PanelButton.js delete mode 100644 config/ags/widget/control_center/Window.js delete mode 100644 config/ags/widget/control_center/buttons/Container.js delete mode 100644 config/ags/widget/control_center/buttons/color_picker.js delete mode 100644 config/ags/widget/control_center/buttons/dark_mode.js delete mode 100644 config/ags/widget/control_center/buttons/dnd.js delete mode 100644 config/ags/widget/control_center/buttons/mic_access.js delete mode 100644 config/ags/widget/control_center/buttons/power_menu.js delete mode 100644 config/ags/widget/control_center/buttons/qs_button.js delete mode 100644 config/ags/widget/control_center/buttons/screen_record.js delete mode 100644 config/ags/widget/control_center/buttons/screenshot.js delete mode 100644 config/ags/widget/control_center/buttons/wallpaper.js delete mode 100644 config/ags/widget/datemenu/PanelButton.js delete mode 100644 config/ags/widget/datemenu/Window.js delete mode 100644 config/ags/widget/hyprsplash/Window.js delete mode 100644 config/ags/widget/network/Bluetooth.js delete mode 100644 config/ags/widget/network/PanelButton.js delete mode 100644 config/ags/widget/network/Wifi.js delete mode 100644 config/ags/widget/network/Window.js delete mode 100644 config/ags/widget/network_speed/PanelButton.js delete mode 100644 config/ags/widget/notifications/PopupWindow.js delete mode 100644 config/ags/widget/notifications/notifications.js delete mode 100644 config/ags/widget/osd/Progress.js delete mode 100644 config/ags/widget/osd/ProgressOsd.js delete mode 100644 config/ags/widget/osd/RegularOsd.js delete mode 100644 config/ags/widget/powermenu/PowerMenuWindow.js delete mode 100644 config/ags/widget/powermenu/VerificationWindow.js delete mode 100644 config/ags/widget/screen_record/PanelButton.js delete mode 100644 config/ags/widget/system_monitor/Window.js delete mode 100644 config/ags/widget/tray/tray.js delete mode 100644 config/ags/widget/wallpaper_picker/Window.js delete mode 100644 config/ags/widget/workspaces/PanelButton.js delete mode 100644 config/ags/windows.js diff --git a/config/ags/README.md b/config/ags/README.md new file mode 100644 index 00000000..71563ed7 --- /dev/null +++ b/config/ags/README.md @@ -0,0 +1,15 @@ + +# 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/ags/apps/settings/bluetooth.ts b/config/ags/apps/settings/bluetooth.ts new file mode 100644 index 00000000..d6224990 --- /dev/null +++ b/config/ags/apps/settings/bluetooth.ts @@ -0,0 +1,12 @@ +import { PageTitle } from "./main"; +import Gtk from "gi://Gtk?version=3.0" + +const bluetooth = await Service.import("bluetooth") + +export const Bluetooth = () => Widget.Box({ + hexpand: true, + vexpand: true, + child: Widget.Label({ + label: "Not implemented yet", + }) +}) \ No newline at end of file diff --git a/config/ags/apps/settings/main.ts b/config/ags/apps/settings/main.ts new file mode 100644 index 00000000..aaf0bb6a --- /dev/null +++ b/config/ags/apps/settings/main.ts @@ -0,0 +1,129 @@ +import { RegularWindow } from "apps/window"; +import { Network } from "./network"; +import { Bluetooth } from "./bluetooth"; +import { Widget as WidgetType } from "types/widgets/widget"; +const hyprland = await Service.import("hyprland") +import Gtk from "gi://Gtk?version=3.0" + +globalThis.OpenSettings = OpenSettings; +let current_window; +const current_tab = Variable("network"); + +export async function OpenSettings(cur_tab: string = "network") { + if (current_window) { + const _current_workspace = hyprland.active.workspace.id; + const _client = hyprland.clients.find(client => { + return (client.class == "com.github.Aylur.ags" && client.title == "Settings") + }) + if (_client && _current_workspace != _client.workspace.id) { + current_window.destroy(); + current_window = undefined; + SettingsWindow(cur_tab); + } + else + current_tab.setValue(cur_tab) + } + else + SettingsWindow(cur_tab); +} + + +function Settings(cur_tab: string) { + current_tab.setValue(cur_tab); + const stack = Widget.Stack({ + // @ts-ignore + shown: current_tab.bind(), + vexpand: true, + hexpand: true, + transition: "crossfade", + children: { + "network": Page(Network(), "Network"), + "bluetooth": Page(Bluetooth(), "Bluetooth") + } + }) + const Row = (name: string, label: string, icon: string = "image-missing") => Widget.Button({ + on_clicked: () => { current_tab.setValue(name) }, + child: Widget.Box({ + children: [ + Widget.Icon(icon), + Widget.Label(label) + ] + }), + class_name: current_tab.bind().as(c => c == name ? "row active" : "row") + }) + const sidebar = Widget.Box({ + vertical: true, + vexpand: true, + class_name: "sidebar", + spacing: 2, + children: [ + Row("network", "Network", "network-wireless-signal-excellent-symbolic"), + Row("bluetooth", "Bluetooth", "bluetooth-active-symbolic"), + Widget.Separator() + ] + }) + return Widget.Box({ + hexpand: true, + vexpand: true, + vertical: false, + css: "background-color: #111418", + children: [ + Widget.Box({ + class_name: "full_sidebar", + vertical: true, + children: [ + Widget.Label({ + class_name: "settings_title", + label: "Settings" + }), + Widget.Scrollable({ + hscroll: "never", + child: sidebar + }), + ] + }), + stack + ] + }); +} + + +export const Page = (widget: Gtk.Widget, name: string) => Widget.Box({ + vertical: true, + children: [ + PageTitle(name), + widget + ] +}) + + +export const PageTitle = (label: string) => Widget.Box({ + class_name: "page_title", + child: Widget.Label({ + label: label, + hpack: "start" + }) +}) + + +export const SettingsWindow = (cur_tab: string) => { + let window = RegularWindow({ + title: "Settings", + default_height: 600, + default_width: 850, + class_name: "settings", + child: Settings(cur_tab), + setup(win) { + current_window = win; + }, + visible: true, + }); + // @ts-ignore + window.on("delete-event", () => { + // @ts-ignore + window.destroy() + current_window = undefined; + return true + }) + return window +} diff --git a/config/ags/apps/settings/network.ts b/config/ags/apps/settings/network.ts new file mode 100644 index 00000000..e200e291 --- /dev/null +++ b/config/ags/apps/settings/network.ts @@ -0,0 +1,214 @@ +import Gtk from "gi://Gtk?version=3.0" +import { timeout } from "resource:///com/github/Aylur/ags/utils.js"; +import { Variable as VariableType } from "types/variable"; +const systemtray = await Service.import("systemtray") + +type AccessPoint = { + bssid: string | null; + address: string | null; + lastSeen: number; + ssid: string | null; + active: boolean; + strength: number; + frequency: number; + iconName: string | undefined; +}; + +const network = await Service.import("network") + +const _scan_timer = Variable(undefined, { + poll: [15000, WifiScan] +}) + + +const network_state = { + "unavailable": "Device is unavailable", + "disconnected": "Device is disconnected", + "prepare": "Preparing to connect...", + "config": "Configuring connection...", + "need_auth": "Authentication required...", + "ip_config": "Obtaining IP address...", + "ip_check": "Verifying IP address...", + "secondaries": "Setting up secondary connections...", + "activated": "Connected", + "deactivating": "Disconnecting...", + "failed": "Connection failed" +}; + +const saved_networks: VariableType = Variable([], { + poll: [5000, () => { + const _saved = Utils.exec(`${App.configDir}/scripts/network.sh --saved`); + return _saved.split("\n") + }] +}) + +function WifiScan() { + network.wifi.scan() + // await Utils.execAsync("nmcli device wifi rescan").catch(print) + return undefined +} + + +const WifiNetwork = (access_point: AccessPoint) => { + const is_saved = saved_networks.value.includes(access_point.ssid!); + const connected = access_point.ssid == network.wifi.ssid; + return Widget.Button({ + class_name: "wifi_network", + on_primary_click: () => { + if (!connected) + Utils.execAsync(`nmcli device wifi connect '${access_point.ssid}'`) + .catch(print); + else if (is_saved) + Utils.execAsync(`${App.configDir}/scripts/network.sh --edit ${access_point.ssid}`) + .catch(print); + }, + on_secondary_click: () => { + if(!connected && is_saved) + Utils.execAsync(`${App.configDir}/scripts/network.sh --edit ${access_point.ssid}`) + .catch(print); + }, + child: Widget.Box({ + class_name: "wifi_network_box", + children: [ + Widget.Icon({ + icon: access_point.iconName, + size: 20 + }), + // @ts-ignore + Widget.Box({ + vertical: true, + children: [ + Widget.Label({ + class_name: "title", + label: access_point.ssid, + hpack: "start" + }), + (connected) + ? Widget.Label({ + class_name: "description", + label: network_state[network.wifi.state], + hpack: "start" + }) + : (is_saved) + ? Widget.Label({ + class_name: "description", + label: "Saved", + hpack: "start" + }) + : undefined + ] + }) + ] + }), + + setup: self => { + self.toggleClassName("active", connected); + } + }) +} + + +const WifiToggle = () => { + const box = Widget.Box({ + class_name: "wifi_toggle", + children: [ + Widget.Box({ + vertical: true, + hexpand: true, + children: [ + Widget.Label({ + hpack: "start", + class_name: "title", + label: "Wi-Fi" + }), + Widget.Label({ + hpack: "start", + class_name: "description", + label: "Find and connect to Wi-Fi networks" + }) + ] + }), + Widget.Switch({ + vexpand: false, + valign: Gtk.Align.CENTER, + hpack: "end", + on_activate(self) { + timeout(5, () => { + if (network.wifi.enabled != self.active) + network.wifi.enabled = self.active + }) + }, + active: Variable(false, { + poll: [500, () => network.wifi.enabled] + }).bind() + }) + ] + }) + return box +} + +function WifiList() { + return Widget.Box({ + vertical: true, + attribute: { + 'updateNetworks': (self) => { + const accessPoints = network.wifi?.access_points || []; + const current_ssid = network.wifi?.ssid; + self.children = Object.values(accessPoints.reduce((a, accessPoint) => { + if (!a[accessPoint.ssid!]) { + a[accessPoint.ssid!] = accessPoint; + // @ts-ignore + a[accessPoint.ssid!].active |= accessPoint.active!; + } + + return a; + // @ts-ignore + }, {})).sort((a: AccessPoint, b: AccessPoint) => { + if (a.ssid === current_ssid) return -1; + if (b.ssid === current_ssid) return 1; + return 0; + // @ts-ignore + }).map((n: AccessPoint) => WifiNetwork(n)); + }, + }, + className: 'wifi_list', + setup: (self) => self.hook(network, self.attribute.updateNetworks), + }) +} + +const nm_applet_required = () => Widget.Box({ + class_name: "error_container", + visible: false, + hexpand: true, + child: Widget.Label({ + label: "Requires running nm-applet for authorization when connecting!", + hpack: "start", + vpack: "center" + }), + setup: self => { + self.hook(systemtray, () => { + const nm_applet = systemtray.items.find(item => item.id == "nm-applet") + if (nm_applet) + self.visible = false; + else + self.visible = true; + }) + } +}) + +export function Network() { + WifiScan() + const box = Widget.Box({ + vertical: true, + children: [ + nm_applet_required(), + WifiToggle(), + WifiList() + ], + }) + return Widget.Scrollable({ + hscroll: "never", + child: box, + vexpand: true + }) +} \ No newline at end of file diff --git a/config/ags/apps/window.ts b/config/ags/apps/window.ts new file mode 100644 index 00000000..4bb803e9 --- /dev/null +++ b/config/ags/apps/window.ts @@ -0,0 +1,3 @@ +import Gtk from "gi://Gtk?version=3.0" + +export const RegularWindow = Widget.subclass(Gtk.Window) diff --git a/config/ags/assets/mixer-symbolic.svg b/config/ags/assets/mixer-symbolic.svg deleted file mode 100644 index ad6cfa85..00000000 --- a/config/ags/assets/mixer-symbolic.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/config/ags/colors.css b/config/ags/colors.css new file mode 100644 index 00000000..2823a6f9 --- /dev/null +++ b/config/ags/colors.css @@ -0,0 +1,46 @@ +@define-color background #131318; +@define-color foreground #e5e1e9; + +@define-color surface #131318; +@define-color onSurface #e5e1e9; +@define-color surfaceContainer #201f25; +@define-color surfaceContainerHigh #2a292f; +@define-color surfaceContainerHighest #35343a; +@define-color surfaceContainerLowest #0e0e13; +@define-color surfaceContainerLow #1c1b20; +@define-color surfaceVariant #47464f; +@define-color onSurfaceVariant #c8c5d0; +@define-color inverseSurface #e5e1e9; +@define-color inverseOnSurface #313036; + +@define-color outline #928f99; +@define-color outlineVariant #47464f; + +@define-color primary #c5c0ff; +@define-color onPrimary #2d2960; +@define-color primaryContainer #444078; +@define-color onPrimaryContainer #e3dfff; + +@define-color secondary #c7c4dc; +@define-color onSecondary #302e42; +@define-color secondaryContainer #49475b; +@define-color onSecondaryContainer #e5e1fb; + +@define-color secondaryFixed #e4dff9; +@define-color secondaryFixedDim #c7c4dc; +@define-color onSecondaryFixed #1b1a2c; + +@define-color primaryFixed #e4dff9; +@define-color primaryFixedDim #c7c4dc; +@define-color onPrimaryFixed #1b1a2c; + +@define-color tertiary #ebb9d0; +@define-color onTertiary #472638; +@define-color tertiaryContainer #ebb9d0; +@define-color onTertiaryContainer #472638; + +@define-color error #ffb4ab; +@define-color onError #690005; +@define-color errorContainer #93000a; +@define-color onErrorContainer #ffdad6; + diff --git a/config/ags/colors.json b/config/ags/colors.json deleted file mode 100644 index ce65474c..00000000 --- a/config/ags/colors.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "colors": { - "dark": { - "background": "#0f1416", - "error": "#ffb4ab", - "error_container": "#93000a", - "inverse_on_surface": "#2c3134", - "inverse_primary": "#05677e", - "inverse_surface": "#dee3e6", - "on_background": "#dee3e6", - "on_error": "#690005", - "on_error_container": "#ffdad6", - "on_primary": "#003543", - "on_primary_container": "#b6ebff", - "on_primary_fixed": "#001f28", - "on_primary_fixed_variant": "#004e60", - "on_secondary": "#1e333b", - "on_secondary_container": "#cfe6f0", - "on_secondary_fixed": "#071e26", - "on_secondary_fixed_variant": "#344a52", - "on_surface": "#dee3e6", - "on_surface_variant": "#bfc8cc", - "on_tertiary": "#2c2e4d", - "on_tertiary_container": "#e0e0ff", - "on_tertiary_fixed": "#161937", - "on_tertiary_fixed_variant": "#424465", - "outline": "#8a9296", - "outline_variant": "#40484c", - "primary": "#87d1eb", - "primary_container": "#004e60", - "primary_fixed": "#b6ebff", - "primary_fixed_dim": "#87d1eb", - "scrim": "#000000", - "secondary": "#b3cad4", - "secondary_container": "#b3cad4", - "secondary_fixed": "#cfe6f0", - "secondary_fixed_dim": "#b3cad4", - "shadow": "#000000", - "surface": "#0f1416", - "surface_bright": "#353a3c", - "surface_container": "#1b2023", - "surface_container_high": "#252b2d", - "surface_container_highest": "#303638", - "surface_container_low": "#171c1f", - "surface_container_lowest": "#0a0f11", - "surface_dim": "#0f1416", - "surface_variant": "#40484c", - "tertiary": "#c2c3eb", - "tertiary_container": "#424465", - "tertiary_fixed": "#e0e0ff", - "tertiary_fixed_dim": "#c2c3eb" - }, - "light": { - "background": "#f5fafd", - "error": "#ba1a1a", - "error_container": "#ffdad6", - "inverse_on_surface": "#edf1f4", - "inverse_primary": "#87d1eb", - "inverse_surface": "#2c3134", - "on_background": "#171c1f", - "on_error": "#ffffff", - "on_error_container": "#410002", - "on_primary": "#ffffff", - "on_primary_container": "#001f28", - "on_primary_fixed": "#001f28", - "on_primary_fixed_variant": "#004e60", - "on_secondary": "#ffffff", - "on_secondary_container": "#071e26", - "on_secondary_fixed": "#071e26", - "on_secondary_fixed_variant": "#344a52", - "on_surface": "#171c1f", - "on_surface_variant": "#40484c", - "on_tertiary": "#ffffff", - "on_tertiary_container": "#161937", - "on_tertiary_fixed": "#161937", - "on_tertiary_fixed_variant": "#424465", - "outline": "#70787c", - "outline_variant": "#bfc8cc", - "primary": "#05677e", - "primary_container": "#b6ebff", - "primary_fixed": "#b6ebff", - "primary_fixed_dim": "#87d1eb", - "scrim": "#000000", - "secondary": "#4c626a", - "secondary_container": "#4c626a", - "secondary_fixed": "#cfe6f0", - "secondary_fixed_dim": "#b3cad4", - "shadow": "#000000", - "source_color": "#31687a", - "surface": "#f5fafd", - "surface_bright": "#f5fafd", - "surface_container": "#eaeff1", - "surface_container_high": "#e4e9ec", - "surface_container_highest": "#dee3e6", - "surface_container_low": "#eff4f7", - "surface_container_lowest": "#ffffff", - "surface_dim": "#d6dbde", - "surface_variant": "#dbe4e8", - "tertiary": "#5a5c7e", - "tertiary_container": "#e0e0ff", - "tertiary_fixed": "#e0e0ff", - "tertiary_fixed_dim": "#c2c3eb" - } - }, - "harmonized_colors": { - "aqua": "#a5f2ff", - "blue": "#0047a3", - "green": "#00fc94", - "grey": "#dcdcdc", - "light_aqua": "#6effee", - "light_green": "#6bf1ae", - "light_red": "#ff9e93", - "red": "#da006d", - "white": "#f6f9fe" - } -} \ No newline at end of file diff --git a/config/ags/config.js b/config/ags/config.js index 227daaf2..2225509b 100644 --- a/config/ags/config.js +++ b/config/ags/config.js @@ -1,7 +1,16 @@ -import onConfigParsed from "./init.js"; -import windows from "./windows.js"; +const entry = App.configDir + '/main.ts' +const outdir = '/tmp/ags/js' -App.config({ - windows: windows, - onConfigParsed: onConfigParsed, -}); +try { + await Utils.execAsync([ + 'bun', 'build', entry, + '--outdir', outdir, + '--external', 'resource://*', + '--external', 'gi://*', + ]) + await import(`file://${outdir}/main.js`) +} catch (error) { + console.error(error) +} + +export { } diff --git a/config/ags/config.json b/config/ags/config.json deleted file mode 100644 index b4aac81b..00000000 --- a/config/ags/config.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "wallpaper": { - "folder": "{{home}}/Pictures/wallpapers", - "current": "wall-31.png" - }, - "theme": { - "dark_mode": true, - "border_radius": "6", - "window": { - "margin": "2", - "border": false, - "opacity": 1 - }, - "bar": { - "position": "bottom", - "opacity": 0, - "shadow": false, - "border": false, - "button_opacity": 0.6, - "button_padding": "4, 8", - "button_spacing": 4, - "button_shadow": false, - "button_border_radius": "6", - "margin": "1", - "padding": "1", - "border_radius": "0", - "launcher_icon": "󰢚", - "workspace_active_width": "0" - } - }, - "osd": { - "regular": { - "position": "bottom", - "vertical": true, - "margin": "0, 12, 60, 0", - "capslock": true, - "mic": true - }, - "progress": { - "position": "bottom", - "vertical": false, - "margin": "12, 12, 2, 12", - "brightness": true, - "volume": true - } - }, - "system_monitor": { - "position": "bottom left", - "margin": "2" - } -} diff --git a/config/ags/functions/globals.js b/config/ags/functions/globals.js deleted file mode 100644 index 538b9260..00000000 --- a/config/ags/functions/globals.js +++ /dev/null @@ -1,19 +0,0 @@ -import recorder from "../services/screen_record.js"; -import brightness from "../services/brightness.js"; -import { capsLockState, configs } from "../vars.js"; -import GLib from "gi://GLib"; - -export default function globals() { - globalThis.TMP = GLib.get_tmp_dir() + "/ags"; - Utils.ensureDirectory(TMP); - globalThis.recorder = recorder; - globalThis.brightness = brightness; - globalThis.update_capslock = () => { - Utils.exec(`brightnessctl -d input3::capslock g`, (stdout) => { - capsLockState.setValue(stdout); - }); - }; - globalThis.moveBar = (pos) => { - configs.theme.bar.position.updateValue(pos); - }; -} diff --git a/config/ags/functions/hyprland/init.js b/config/ags/functions/hyprland/init.js deleted file mode 100644 index a3bed8fa..00000000 --- a/config/ags/functions/hyprland/init.js +++ /dev/null @@ -1,7 +0,0 @@ -import windowAnimation from "./window_animation.js"; -import windowBlur from "./window_blur.js"; - -export default function initHyprland() { - windowAnimation(); - windowBlur(); -} diff --git a/config/ags/functions/hyprland/window_animation.js b/config/ags/functions/hyprland/window_animation.js deleted file mode 100644 index 1d93ccc0..00000000 --- a/config/ags/functions/hyprland/window_animation.js +++ /dev/null @@ -1,13 +0,0 @@ -import { sendBatch } from "../utils.js"; -import { configs } from "../../vars.js"; - -export default function windowAnimation() { - sendBatch( - App.windows - .filter((win) => !!win.animation) - .map( - (win) => - `layerrule animation ${win.animation === "slide top" ? `slide ${configs.theme.bar.position.value}` : win.animation}, ${win.name}`, - ), - ); -} diff --git a/config/ags/functions/hyprland/window_blur.js b/config/ags/functions/hyprland/window_blur.js deleted file mode 100644 index 3a3ec05b..00000000 --- a/config/ags/functions/hyprland/window_blur.js +++ /dev/null @@ -1,14 +0,0 @@ -import { sendBatch } from "../utils.js"; - -export default function windowBlur() { - const noIgnorealpha = ["verification__window", "powermenu__window"]; - - sendBatch( - App.windows.flatMap(({ name }) => [ - `layerrule blur, ${name}`, - noIgnorealpha.some((skip) => name?.includes(skip)) - ? "" - : `layerrule ignorealpha 0.3, ${name}`, - ]), - ); -} diff --git a/config/ags/functions/monitor_configuration.js b/config/ags/functions/monitor_configuration.js deleted file mode 100644 index 6e7b2b8e..00000000 --- a/config/ags/functions/monitor_configuration.js +++ /dev/null @@ -1,127 +0,0 @@ -import { configPath } from "../services/configuration.js"; -import { HOME, configs } from "../vars.js"; -import { replacePlaceholders as rep } from "./utils.js"; -import Gio from "gi://Gio"; - -//sorry (?) - -export default function() { - const wallpaper = configs.wallpaper; - const theme = configs.theme; - const bar = theme.bar; - const osd = configs.osd; - const sysmonitor = configs.system_monitor; - const window = theme.window; - - Utils.monitorFile(configPath, (file, type) => { - // Monitor non Utils.writeFile event - if (type === Gio.FileMonitorEvent.ATTRIBUTE_CHANGED) { - const configJson = JSON.parse(Utils.readFile(file.get_path()) || "{}"); - const wallpaperJson = configJson.wallpaper; - const themeJson = configJson.theme; - const windowJson = themeJson.window; - const barJson = themeJson.bar; - const osdJson = configJson.osd; - const sysmonitorJson = configJson.system_monitor; - - if (wallpaper.folder.value != rep(wallpaperJson.folder, { home: HOME })) - wallpaper.folder.setValue(rep(wallpaperJson.folder, { home: HOME })); - - if (wallpaper.current.value != wallpaperJson.current) - wallpaper.current.setValue(wallpaperJson.current); - - if (theme.dark_mode.value != themeJson.dark_mode) - theme.dark_mode.setValue(themeJson.dark_mode); - - if (window.margin.value != windowJson.margin) - window.margin.setValue(windowJson.margin); - - if (window.opacity.value != windowJson.opacity) - window.opacity.setValue(windowJson.opacity); - - if (window.border.value != windowJson.border) - window.border.setValue(windowJson.border); - - if (theme.border_radius.value != themeJson.border_radius) - theme.border_radius.setValue(themeJson.border_radius); - - if (bar.position.value != barJson.position) - bar.position.setValue(barJson.position); - - if (bar.border.value != barJson.border) - bar.border.setValue(barJson.border); - - if (bar.opacity.value != barJson.opacity) - bar.opacity.setValue(barJson.opacity); - - if (bar.button_opacity.value != barJson.button_opacity) - bar.button_opacity.setValue(barJson.button_opacity); - - if (bar.shadow.value != barJson.shadow) - bar.shadow.setValue(barJson.shadow); - - if (bar.button_padding.value != barJson.button_padding) - bar.button_padding.setValue(barJson.button_padding); - - if (bar.button_spacing.value != barJson.button_spacing) - bar.button_spacing.setValue(barJson.button_spacing); - - if (bar.button_shadow.value != barJson.button_shadow) - bar.button_shadow.setValue(barJson.button_shadow); - - if (bar.button_border_radius.value != barJson.button_border_radius) - bar.button_border_radius.setValue(barJson.button_border_radius); - - if (bar.margin.value != barJson.margin) - bar.margin.setValue(barJson.margin); - - if (bar.padding.value != barJson.padding) - bar.padding.setValue(barJson.padding); - - if (bar.border_radius.value != barJson.border_radius) - bar.border_radius.setValue(barJson.border_radius); - - if (bar.launcher_icon.value != barJson.launcher_icon) - bar.launcher_icon.setValue(barJson.launcher_icon); - - if (bar.workspace_active_width.value != barJson.workspace_active_width) - bar.workspace_active_width.setValue(barJson.workspace_active_width); - - if (osd.progress.position.value != osdJson.progress.position) - osd.progress.position.setValue(osdJson.progress.position); - - if (osd.regular.position.value != osdJson.regular.position) - osd.regular.position.setValue(osdJson.regular.position); - - if (osd.progress.vertical.value != osdJson.progress.vertical) - osd.progress.vertical.setValue(osdJson.progress.vertical); - - if (osd.regular.vertical.value != osdJson.regular.vertical) - osd.regular.vertical.setValue(osdJson.regular.vertical); - - if (osd.regular.margin.value != osdJson.regular.margin) - osd.regular.margin.setValue(osdJson.regular.margin); - - if (osd.progress.margin.value != osdJson.progress.margin) - osd.progress.margin.setValue(osdJson.progress.margin); - - if (osd.regular.capslock.value != osdJson.regular.capslock) - osd.regular.capslock.setValue(osdJson.regular.capslock); - - if (osd.regular.mic.value != osdJson.regular.mic) - osd.regular.mic.setValue(osdJson.regular.mic); - - if (osd.progress.brightness.value != osdJson.progress.brightness) - osd.progress.brightness.setValue(osdJson.progress.brightness); - - if (osd.progress.volume.value != osdJson.progress.volume) - osd.progress.volume.setValue(osdJson.progress.volume); - - if (sysmonitor.position.value != sysmonitorJson.position) - sysmonitor.position.setValue(sysmonitorJson.position); - - if (sysmonitor.margin.value != sysmonitorJson.margin) - sysmonitor.margin.setValue(sysmonitorJson.margin); - } - }); -} diff --git a/config/ags/functions/theme/ags.js b/config/ags/functions/theme/ags.js deleted file mode 100644 index f0c33d08..00000000 --- a/config/ags/functions/theme/ags.js +++ /dev/null @@ -1,135 +0,0 @@ -import { isVertical, matugenStringify, posIndex } from "../utils.js"; -import { configs } from "../../vars.js"; - -export const format = (str, four_values = true, px = true) => { - let splitted = str - .split(",") - .map((item) => `${item}${px ? `px` : ""}`.trim()); - - let result = splitted.join(" "); - if (four_values) { - switch (splitted.length) { - case 1: - result = `${splitted[0]} `.repeat(4); - break; - case 2: - result = `${splitted[0]} ${splitted[1]} ${splitted[0]} ${splitted[1]}`; - break; - case 3: - result = `${splitted[0]} ${splitted[1]} ${splitted[2]} ${splitted[1]}`; - break; - } - } - - return result; -}; - -function switchArray(arr) { - var temp = arr[0]; - arr[0] = arr[1]; - arr[1] = temp; - - temp = arr[2]; - arr[2] = arr[3]; - arr[3] = temp; - - return arr; -} - -export function setScssVariable({ - key = "", - value = "", - need_format = true, - four_values = true, - bar_pos = configs.theme.bar.position.value, -}) { - let data = { - window_margin: "0", - border_radius: "0", - bar_border_radius: "0", - bar_margin: "0", - workspace_active_width: "30", - dark_mode: false, - osd_regular_margin: "0", - osd_progress_margin: "0", - bar_opacity: 1.0, - bar_button_opacity: 1.0, - panel_button_padding: "0", - bar_padding: "0", - bar_shadow: false, - bar_button_shadow: false, - bar_button_border_radius: "0", - system_monitor_margin: "0", - bar_border: false, - window_opacity: 0.7, - window_border: false, - }; - - let idx = [2, 3, 0, 1]; - - data.window_margin = format(configs.theme.window.margin.value); - data.border_radius = format(configs.theme.border_radius.value); - data.bar_border_radius = format(configs.theme.bar.border_radius.value); - data.bar_margin = format(configs.theme.bar.margin.value); - data.dark_mode = configs.theme.dark_mode.value.toString(); - data.workspace_active_width = format( - configs.theme.bar.workspace_active_width.value, - false, - ); - data.osd_regular_margin = format(configs.osd.regular.margin.value); - data.osd_progress_margin = format(configs.osd.progress.margin.value); - data.bar_opacity = configs.theme.bar.opacity.value; - data.bar_button_opacity = configs.theme.bar.button_opacity.value; - data.bar_shadow = configs.theme.bar.shadow.value; - data.bar_button_shadow = configs.theme.bar.button_shadow.value; - data.panel_button_padding = format(configs.theme.bar.button_padding.value); - data.bar_padding = format(configs.theme.bar.padding.value); - data.bar_button_border_radius = format( - configs.theme.bar.button_border_radius.value, - ); - data.bar_border = configs.theme.bar.border.value; - data.system_monitor_margin = format(configs.system_monitor.margin.value); - data.window_opacity = configs.theme.window.opacity.value; - data.window_border = configs.theme.window.border.value; - - if (isVertical(bar_pos)) { - data.panel_button_padding = switchArray( - data.panel_button_padding.split(" "), - ).join(" "); - } - - let update = {}; - if (key != "" && value != "") { - update[key] = need_format ? format(value, four_values) : value; - } - let merged = { ...data, ...update }; - - merged.window_margin = merged.window_margin.split(" "); - const tempWindowMargin = - Number(merged.window_margin[posIndex(bar_pos)].replace("px", "")) / 2; - merged.window_margin[posIndex(bar_pos)] = `${tempWindowMargin}px`; - merged.window_margin = merged.window_margin.join(" "); - merged.bar_margin = merged.bar_margin.split(" "); - merged.bar_margin[idx[posIndex(bar_pos)]] = `${tempWindowMargin}px`; - merged.bar_margin = merged.bar_margin.join(" "); - - let result = ""; - - Object.entries(merged).forEach(([key, value]) => { - result += `$${key}: ${value};\n`; - }); - - Utils.writeFile(result, App.configDir + "/style/vars.scss"); -} - -function setScssColors(theme) { - Utils.writeFile( - matugenStringify("${{key}}: {{value}};", theme), - App.configDir + "/style/colors.scss", - ); -} - -export default function setAgs(theme) { - setScssVariable({}); - setScssColors(theme); -} diff --git a/config/ags/functions/theme/gtk.js b/config/ags/functions/theme/gtk.js deleted file mode 100644 index 73efcaa6..00000000 --- a/config/ags/functions/theme/gtk.js +++ /dev/null @@ -1,46 +0,0 @@ -import { HOME, configs } from "../../vars.js"; -import Gio from "gi://Gio"; - -const settings = new Gio.Settings({ - schema: "org.gnome.desktop.interface", -}); - -function setGtkSetting(themeScheme) { - settings.reset("color-scheme"); - settings.set_string("color-scheme", `prefer-${themeScheme}`); - settings.set_string( - "gtk-theme", - `adw-gtk3${themeScheme == "dark" ? "-dark" : ""}`, - ); -} - -export default async function setGtk(theme, themeScheme) { - if (themeScheme === undefined) { - themeScheme = configs.theme.dark_mode.value ? "dark" : "light"; - } - - if (theme === undefined) { - theme = JSON.parse(Utils.readFile(App.configDir + "/colors.json") || "{}") - .colors[themeScheme]; - } - - const primaryColor = theme.primary; - const bgColor = theme.background; - const gtkCss = [ - `accent_bg_color ${primaryColor};`, - `view_bg_color alpha(${bgColor}, ${configs.theme.window.opacity.value});`, - `sidebar_bg_color alpha(${bgColor}, ${configs.theme.window.opacity.value});`, - `headerbar_bg_color ${bgColor};`, - `popover_bg_color alpha(${bgColor}, ${configs.theme.window.opacity.value});`, - ]; - Utils.writeFile( - gtkCss - .map((vars) => { - return "@define-color " + vars; - }) - .join(`\n`), - HOME + "/.themes/colors.css", - ).then(() => { - setGtkSetting(themeScheme); - }); -} diff --git a/config/ags/functions/theme/hyprland.js b/config/ags/functions/theme/hyprland.js deleted file mode 100644 index 069d7c55..00000000 --- a/config/ags/functions/theme/hyprland.js +++ /dev/null @@ -1,34 +0,0 @@ -import { configs } from "../../vars.js"; -import { isVertical, posIndex, sendBatch } from "../utils.js"; -import { format } from "./ags.js"; - -export default function setHyprland(theme) { - const bgColor = theme.background.replace("#", ""); - const primaryColor = theme.primary.replace("#", ""); - let margin = format(configs.theme.window.margin.value, true, false); - margin = margin.split(" "); - const marginValue = Number( - margin[posIndex(configs.theme.bar.position.value)], - ); - margin[posIndex(configs.theme.bar.position.value)] = `${marginValue / q}`; - margin = margin.join(", "); - sendBatch([ - `decoration:col.shadow rgb(${bgColor})`, - `decoration:rounding ${configs.theme.border_radius.value.split(",")[0].trim()}`, - `general:col.active_border rgb(${primaryColor})`, - `general:gaps_out ${margin}`, - `animation workspaces,1,7,menu_decel,${isVertical(configs.theme.bar.position.value) ? `slidevert` : "slide"}`, - ]); -} - -export function setGapsOut() { - const bar_pos = configs.theme.bar.position.value; - const value = configs.theme.window.margin.value; - let margin = format(value, true, false); - margin = margin.split(" "); - const marginValue = Number(margin[posIndex(bar_pos)]); - margin[posIndex(bar_pos)] = `${marginValue / 2}`; - margin = margin.join(", "); - - sendBatch([`general:gaps_out ${margin}`]); -} diff --git a/config/ags/functions/theme/init.js b/config/ags/functions/theme/init.js deleted file mode 100644 index 232233d2..00000000 --- a/config/ags/functions/theme/init.js +++ /dev/null @@ -1,42 +0,0 @@ -import setAgs from "./ags.js"; -import setHyprland from "./hyprland.js"; -import setGtk from "./gtk.js"; -import Gio from "gi://Gio"; -import { applyCss, sh } from "../utils.js"; -import { configs } from "../../vars.js"; - -export function setTheme() { - let colors = Utils.readFile(App.configDir + "/colors.json"); - - if (colors === "") { - sh(`matugen color hex "#282828" --json hex`).then((out) => { - colors = out; - Utils.writeFile( - JSON.stringify(JSON.parse(out), null, 2), - App.configDir + "/colors.json", - ).catch(print); - }); - } - const themeJson = JSON.parse(colors || "{}"); - const themeMode = configs.theme.dark_mode.value ? "dark" : "light"; - const theme = themeJson["colors"][themeMode]; - const harmonizedColors = themeJson.harmonized_colors; - - setAgs(theme); - setHyprland(theme); - setGtk(theme, themeMode); -} - -function monitorTheme() { - Utils.monitorFile(App.configDir + "/colors.json", (_, eventType) => { - if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) { - setTheme(); - } - }); - Utils.monitorFile(App.configDir + "/style/", applyCss); -} - -export default function initTheme() { - monitorTheme(); - setTheme(); -} diff --git a/config/ags/functions/theme/matugen.js b/config/ags/functions/theme/matugen.js deleted file mode 100644 index 5fa13f81..00000000 --- a/config/ags/functions/theme/matugen.js +++ /dev/null @@ -1,10 +0,0 @@ -import { sh } from "../utils.js"; - -export function generateColor(path) { - sh(`matugen image ${path} --json hex`).then((out) => { - Utils.writeFile( - JSON.stringify(JSON.parse(out), null, 2), - App.configDir + "/colors.json", - ).catch(print); - }); -} diff --git a/config/ags/functions/utils.js b/config/ags/functions/utils.js deleted file mode 100644 index c6d1e522..00000000 --- a/config/ags/functions/utils.js +++ /dev/null @@ -1,159 +0,0 @@ -import GLib from "gi://GLib?version=2.0"; -const hyprland = await Service.import("hyprland"); - -const substitutes = { - "transmission-gtk": "transmission", - "blueberry.py": "blueberry", - Caprine: "facebook-messenger", - "Alacritty-symbolic": "terminal-symbolic", - "com.raggesilver.BlackBox-symbolic": "terminal-symbolic", - "org.wezfurlong.wezterm-symbolic": "terminal-symbolic", - "audio-headset-bluetooth": "audio-headphones-symbolic", - "audio-card-analog-usb": "audio-speakers-symbolic", - "audio-card-analog-pci": "audio-card-symbolic", - "preferences-system": "emblem-system-symbolic", - "com.github.Aylur.ags-symbolic": "controls-symbolic", - "com.github.Aylur.ags": "controls-symbolic", -}; - -export function icon(name, fallback = "image-missing-symbolic") { - if (!name) return fallback || ""; - - if (GLib.file_test(name, GLib.FileTest.EXISTS)) return name; - - const icon = substitutes[name] || name; - if (Utils.lookUpIcon(icon)) return icon; - - return fallback; -} - -export const sendBatch = (batch) => { - const cmd = batch - .filter((x) => !!x) - .map((x) => `keyword ${x}`) - .join("; "); - - hyprland.message(`[[BATCH]]/${cmd}`); -}; - -export async function sh(cmd) { - return Utils.execAsync(cmd).catch((err) => { - console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err); - return ""; - }); -} -export async function bash(strings, ...values) { - const cmd = - typeof strings === "string" - ? strings - : strings.flatMap((str, i) => str + `${values[i] ?? ""}`).join(""); - - return Utils.execAsync(["bash", "-c", cmd]).catch((err) => { - console.error(cmd, err); - return ""; - }); -} - -export function matugenStringify(format, json) { - let result = ""; - - for (let key in json) { - let value = json[key]; - result += format.replace("{{key}}", key).replace("{{value}}", value) + "\n"; - } - - return result; -} - -export function applyCss() { - const scss = App.configDir + "/style/main.scss"; - const css = TMP + "/style.css"; - - sh(`sass ${scss} ${css}`).then(() => { - App.resetCss(); - App.applyCss(css); - }); -} - -const isObject = (item) => { - return item && typeof item === "object" && !Array.isArray(item); -}; - -export function deepMerge(target, ...sources) { - if (!sources.length) return target; - const source = sources.shift(); - - if (isObject(target) && isObject(source)) { - for (const key in source) { - if (isObject(source[key])) { - if (!target[key]) - Object.assign(target, { - [key]: {}, - }); - deepMerge(target[key], source[key]); - } else { - Object.assign(target, { - [key]: source[key], - }); - } - } - } - - return deepMerge(target, ...sources); -} - -export function replacePlaceholders(str, data) { - if (typeof str !== "string") { - return str; - } - return str.replace(/\{\{(\w+)\}\}/g, (match, key) => { - return data[key] || match; - }); -} - -export function reverseReplace(str, data) { - for (const key in data) { - if (data.hasOwnProperty(key)) { - const value = data[key]; - const regex = new RegExp(value, "g"); - str = str.replace(regex, `{{${key}}}`); - } - } - return str; -} - -export function isVertical(pos) { - return pos === "left" || pos === "right"; -} - -export const posIndex = (pos) => { - switch (pos) { - case "top": - return 0; - case "right": - return 1; - case "bottom": - return 2; - default: - return 3; - } -}; - -export const layoutPos = (pos, layout) => { - const win = { - top: {}, - left: { - "top-right": "bottom-left", - }, - right: { - "top-right": "bottom-right", - "top-left": "top-right", - }, - bottom: { - "top-left": "bottom-left", - "top-right": "bottom-right", - }, - }; - - return win[pos][layout] ?? layout; -}; diff --git a/config/ags/functions/wallpaper.js b/config/ags/functions/wallpaper.js deleted file mode 100644 index c3c8f9cf..00000000 --- a/config/ags/functions/wallpaper.js +++ /dev/null @@ -1,33 +0,0 @@ -import { configs, HOME } from "../vars.js"; -import { sh } from "./utils.js"; -import { generateColor } from "./theme/matugen.js"; -import Gio from "gi://Gio"; - -export function cpWallpaper(filename) { - const folder = configs.wallpaper.folder.value; - const path = folder + "/" + filename; - sh(`cp ${path} ${HOME}/.config/background`); -} - -export function setWallpaper(path) { - generateColor(path); - sh([ - "swww", - "img", - "--transition-type", - "any", - "--transition-fps", - "60", - path, - ]); -} - -export default function initWallpaper() { - Utils.monitorFile(`${HOME}/.config/background/`, (file, eventType) => { - if (eventType === Gio.FileMonitorEvent.CHANGES_DONE_HINT) { - setWallpaper(file.get_path()); - } - }); - - sh("swww-daemon --format xrgb"); -} diff --git a/config/ags/init.js b/config/ags/init.js deleted file mode 100644 index e8be8a81..00000000 --- a/config/ags/init.js +++ /dev/null @@ -1,16 +0,0 @@ -// import { initTheme, initWallpaper, setWallpaper } from "./functions/theme.js"; -import initWallpaper from "./functions/wallpaper.js"; -import watchConfiguration from "./functions/monitor_configuration.js"; -import initHyprland from "./functions/hyprland/init.js"; -import initTheme from "./functions/theme/init.js"; -import globals from "./functions/globals.js"; -import { setupWindows } from "./windows.js"; - -export default function() { - globals(); - setupWindows(); - initWallpaper(); - initTheme(); - initHyprland(); - watchConfiguration(); -} diff --git a/config/ags/main.ts b/config/ags/main.ts new file mode 100644 index 00000000..016a6940 --- /dev/null +++ b/config/ags/main.ts @@ -0,0 +1,82 @@ +"use strict"; +// Import +import Gdk from 'gi://Gdk'; +// widgets +import { Bar, BarCornerTopLeft, BarCornerTopRight } from './modules/bar.ts'; +import { Notifications } from "./modules/notificationPopups.ts" +import { applauncher } from "./modules/applauncher.js" +import { media } from "./modules/media.ts" +import { cliphist } from "./modules/cliphist.ts" +import { sidebar } from "./modules/sidebar/main.ts" +import {} from 'apps/settings/main.ts'; +import Window from 'types/widgets/window'; +const GLib = imports.gi.GLib; + + +const range = (length: number, start = 1) => Array.from({ length }, (_, i) => i + start); +function forMonitors(widget: (index: number) => Window): Window[] { + const n = Gdk.Display.get_default()?.get_n_monitors() || 1; + return range(n, 0).map(widget).flat(1); +} +function forMonitorsAsync(widget: (index: number) => Promise>) { + const n = Gdk.Display.get_default()?.get_n_monitors() || 1; + return range(n, 0).forEach((n) => widget(n).catch(print)) +} + +const Windows = () => [ + forMonitors(Notifications), + forMonitors(BarCornerTopLeft), + forMonitors(BarCornerTopRight), + media, + applauncher, + cliphist, + sidebar, +]; + +const CLOSE_ANIM_TIME = 210; +const closeWindowDelays = {}; +for (let i = 0; i < (Gdk.Display.get_default()?.get_n_monitors() || 1); i++) { + closeWindowDelays[`osk${i}`] = CLOSE_ANIM_TIME; +} + +App.config({ + windows: Windows().flat(1), + // @ts-ignore + closeWindowDelay: closeWindowDelays, + onConfigParsed: function () { + }, +}); + +function ReloadCSS() { + App.resetCss() + // Utils.execAsync(`cp -f -r ${GLib.get_home_dir()}/dotfiles/material-colors/generated/svg/ ${App.configDir}/`).catch(print) + App.applyCss(`${App.configDir}/style.css`) + App.applyCss(`${App.configDir}/style-apps.css`) +} + +function ReloadGtkCSS() { + App.applyCss(`${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`) + ReloadCSS() +} + +Utils.monitorFile( + `${App.configDir}/style.css`, + ReloadCSS +) + +Utils.monitorFile( + `${App.configDir}/style-apps.css`, + ReloadCSS +) + +Utils.monitorFile( + `${GLib.get_home_dir()}/.cache/material/colors.json`, + ReloadCSS +) + +Utils.monitorFile( + `${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`, + ReloadGtkCSS +) +forMonitorsAsync(Bar) +ReloadGtkCSS() diff --git a/config/ags/modules/applauncher.ts b/config/ags/modules/applauncher.ts new file mode 100644 index 00000000..1166e627 --- /dev/null +++ b/config/ags/modules/applauncher.ts @@ -0,0 +1,179 @@ + +const { query } = await Service.import("applications") +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); +const Gio = imports.gi.Gio; +const { Gtk } = imports.gi; +const GLib = imports.gi.GLib; +const WINDOW_NAME = "applauncher" +import Box from 'types/widgets/box'; +import popupwindow from './misc/popupwindow.ts'; +import { Application } from 'types/service/applications'; + + +const LAUNCH_COUNT_FILE = Gio.File.new_for_path( + GLib.build_filenamev([GLib.get_home_dir(), '.cache', 'launch_counts.json']) +); + +function readLaunchCounts() { + try { + if (!LAUNCH_COUNT_FILE.query_exists(null)) { + return {}; + } + const [, contents] = LAUNCH_COUNT_FILE.load_contents(null); + return JSON.parse(decoder.decode(contents)); + } catch (error) { + return {}; + } +} + +function writeLaunchCounts(launchCounts: number) { + const data = JSON.stringify(launchCounts, null, 2); + LAUNCH_COUNT_FILE.replace_contents( + encoder.encode(data), + null, + false, + Gio.FileCreateFlags.REPLACE_DESTINATION, + null + ); +} + +function incrementLaunchCount(appName: string) { + const launchCounts = readLaunchCounts(); + launchCounts[appName] = (launchCounts[appName] || 0) + 1; + writeLaunchCounts(launchCounts); +} + +function sortApplicationsByLaunchCount(applications: Box[]) { + const launchCounts = readLaunchCounts() + return applications.sort((a: Box, b: Box) => { + const countA = launchCounts[a.attribute.app.name] || 0 + const countB = launchCounts[b.attribute.app.name] || 0 + return countB - countA + }) +} + +function AppItem(app: Application): Box { + let clickCount = 0; + const button = Widget.Button({ + class_name: "application_container", + child: Widget.Box({ + children: [ + Widget.Icon({ + class_name: "application_icon", + // @ts-ignore + icon: Utils.lookUpIcon(app.icon_name) ? app.icon_name : "image-missing", + size: 42, + }), + Widget.Label({ + class_name: "application_label", + label: app.name, + xalign: 0, + vpack: "center", + truncate: "end", + }), + ] + }) + }) + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 2) { + incrementLaunchCount(app.name); + App.closeWindow(WINDOW_NAME); + app.launch(); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return Widget.Box({ + attribute: { app }, + orientation: Gtk.Orientation.VERTICAL, + children: [ + button, + Widget.Separator({ + class_name: "application_divider", + orientation: Gtk.Orientation.HORIZONTAL + }) + ], + }) +}; + +const Applauncher = ({ width = 500, height = 500, spacing = 12 }) => { + let applications: Box[]; + + const list = Widget.Box({ + vertical: true, + spacing, + }) + + function repopulate() { + applications = query("").map(AppItem) + applications = sortApplicationsByLaunchCount(applications) + list.children = applications + } + repopulate() + + const entry = Widget.Entry({ + hexpand: true, + class_name: "applauncher_entry", + placeholder_text: "Search", + + on_accept: () => { + const results = applications.filter((item) => item.visible) + if (results[0]) { + App.toggleWindow(WINDOW_NAME) + results[0].attribute.app.launch() + } + }, + + on_change: ({ text }) => applications.forEach(item => { + item.visible = item.attribute.app.match(text ?? "") + }), + }) + + return Widget.Box({ + vertical: true, + css: `margin: ${spacing * 2}px;`, + class_name: "applauncher_box", + margin_top: 14, + margin_left: 14, + children: [ + entry, + + Widget.Scrollable({ + hscroll: "never", + css: `min-width: ${width}px;` + + `min-height: ${height}px;`, + child: list, + }), + ], + setup: self => self.hook(App, (_, windowName, visible) => { + if (windowName !== WINDOW_NAME) + return + + if (visible) { + repopulate() + entry.text = "" + } + }), + }) +} + +export const applauncher = popupwindow({ + name: WINDOW_NAME, + + class_name: "applauncher", + visible: false, + keymode: "exclusive", + child: Applauncher({ + width: 500, + height: 500, + spacing: 0, + }), + anchor: ["bottom", "left"] +}) diff --git a/config/ags/modules/bar.ts b/config/ags/modules/bar.ts new file mode 100644 index 00000000..e19d4c67 --- /dev/null +++ b/config/ags/modules/bar.ts @@ -0,0 +1,451 @@ +const hyprland = await Service.import("hyprland") +const battery = await Service.import("battery") +const systemtray = await Service.import("systemtray") +const audio = await Service.import("audio") +const network = await Service.import("network") +const { Gtk, GLib, Gio } = imports.gi; +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); +import { OpenSettings } from "apps/settings/main.ts"; +import { enableClickThrough } from "./misc/clickthrough.js"; +import { RoundedCorner } from "./misc/cairo_roundedcorner.js"; +import { Client, Workspace } from "types/service/hyprland.js" +import Button from "types/widgets/button.js" +import Icon from "types/widgets/icon.js" +import { FileEnumerator, FileInfo } from "types/@girs/gio-2.0/gio-2.0.cjs" +const mpris = await Service.import("mpris") + + +function checkKeymap() { + const layout = Utils.execAsync(`hyprctl devices -j | jq -r '.keyboards[] | select(.main == true) | .active_keymap' | tail -n1 | cut -c1-2 | tr 'A-Z' 'a-z'`) + .then(out => { return out }) + .catch(err => { print(err); return "en" }); + return layout; +} + +const keyboard_layout = Variable("en") +keyboard_layout.setValue(await checkKeymap()) +hyprland.connect("keyboard-layout", (hyprland, keyboardname, layoutname) => { + keyboard_layout.setValue(layoutname.trim().toLowerCase().substr(0, 2)) +}) + +const time = Variable("", { + poll: [1000, 'date "+%I:%M %p"'], +}) + +const date = Variable("", { + poll: [1000, 'date "+%Y-%m-%d"'], +}) + + +function getIconNameFromClass(windowClass: string) { + let formattedClass = windowClass.replace(/\s+/g, '-').toLowerCase(); + let homeDir = GLib.get_home_dir(); + let systemDataDirs = GLib.get_system_data_dirs().map(dir => dir + '/applications'); + let dataDirs = systemDataDirs.concat([homeDir + '/.local/share/applications']); + let icon: string | undefined; + + for (let dir of dataDirs) { + let applicationsGFile = Gio.File.new_for_path(dir); + + let enumerator: FileEnumerator; + try { + enumerator = applicationsGFile.enumerate_children('standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); + } catch (e) { + continue; + } + + let fileInfo: FileInfo | null; + while ((fileInfo = enumerator.next_file(null)) !== null) { + let desktopFile = fileInfo.get_name(); + if (desktopFile.endsWith('.desktop')) { + let fileContents = GLib.file_get_contents(dir + '/' + desktopFile); + let matches = /Icon=(\S+)/.exec(decoder.decode(fileContents[1])); + if (matches && matches[1]) { + if (desktopFile.toLowerCase().includes(formattedClass)) { + icon = matches[1]; + break; + } + } + } + } + + enumerator.close(null); + if (icon) break; + } + return Utils.lookUpIcon(icon) ? icon : "image-missing"; +} + +const dispatch = (ws: string) => hyprland.messageAsync(`dispatch workspace ${ws}`).catch(print); + + +function Workspaces() { + const activeId = hyprland.active.workspace.bind("id"); + let workspaceButtons = new Map(); + + function createWorkspaceButton(id: Number) { + const button = Widget.Button({ + on_clicked: () => dispatch(`${id}`), + child: Widget.Label(`${id}`), + class_name: activeId.as(i => `${i === id ? "active" : ""}`), + }); + return button; + } + + function updateWorkspaceButtons(workspaces: Workspace[]): Array> { + workspaces.sort((a, b) => a.id - b.id); + + const updatedButtons = new Map(); + + workspaces.forEach(({ id }) => { + if (workspaceButtons.has(id)) { + updatedButtons.set(id, workspaceButtons.get(id)); + } else { + updatedButtons.set(id, createWorkspaceButton(id)); + } + }); + if (workspaceButtons != updatedButtons) + workspaceButtons = updatedButtons; + + return Array.from(workspaceButtons.values()); + } + + const workspaceButtonsArray = hyprland.bind("workspaces").as(updateWorkspaceButtons); + + return Widget.EventBox({ + onScrollUp: () => dispatch('+1'), + onScrollDown: () => dispatch('-1'), + child: Widget.Box({ + children: workspaceButtonsArray, + class_name: "workspaces", + }), + }); +} + + +function Clock() { + return Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "clock", + children: [ + Widget.Label({ + class_name: "time", + label: time.bind(), + }), + Widget.Label({ + class_name: "date", + label: date.bind(), + }) + ], + }) +} + + +function BatteryLabel() { + const icon = battery.bind("icon_name"); + + const isVisible = battery.bind("percent").as(p => p < 100); + + return Widget.Box({ + class_name: "battery", + visible: isVisible, + children: [ + Widget.Icon({ icon }), + Widget.Label({ + label: battery.bind("percent").as(p => `${p > 0 ? p : 0}%`), + }), + ], + }); +} + + +function SysTray() { + const items = systemtray.bind("items") + .as(items => items.map(item => { + if (item.id.trim() != "nm-applet") { + return Widget.Button({ + child: Widget.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"), + }) + } else { + return undefined + } + })) + + // @ts-ignore + return Widget.Box({ + class_name: "tray", + spacing: 5, + children: items, + }) +} + + +function AppLauncher() { + const button = Widget.Button({ + class_name: "filled_tonal_button awesome_icon", + on_clicked: () => { + App.toggleWindow("applauncher") + }, + child: Widget.Label( + "\uf002" + ) + }) + + return button +} + + +function Wifi() { + const button = Widget.Button({ + class_name: "bar_wifi awesome_icon", + on_primary_click: () => { + OpenSettings("network") + }, + on_secondary_click: (_, event) => { + const nm_applet = systemtray.items.find(item => item.id == "nm-applet") + if (nm_applet) { + nm_applet.openMenu(event) + } else { + Utils.execAsync("nm-connection-editor").catch(print) + } + }, + child: Widget.Icon({ + icon: "network-wireless-offline-symbolic" + }), + tooltip_text: 'Disabled' + }).hook(network, self => { + if (network.wifi.enabled) { + self.tooltip_text = network.wifi.ssid || 'Unknown'; + self.child.icon = network.wifi.icon_name; + } else { + self.tooltip_text = 'Disabled' + self.child.icon = "network-wireless-offline-symbolic"; + } + }) + + return button +} + + +function MediaPlayer() { + let metadata = mpris.players[0]?.metadata; + const button = Widget.Button({ + class_name: "filled_tonal_button awesome_icon", + on_primary_click: () => { + App.toggleWindow("media") + // Utils.execAsync(["ags", "-t", "media"]) + }, + on_secondary_click: () => { + Utils.execAsync(["playerctl", "play-pause"]).catch(print) + }, + child: Widget.Label( + "" + ), + visible: false, + tooltip_text: "Unknown" + }).hook(mpris, self => { + if (mpris.players.length > 0) { + self.visible = true; + metadata = mpris.players[0]?.metadata; + if (metadata) + self.tooltip_text = `${metadata["xesam:artist"]} - ${metadata["xesam:title"]}`; + } else { + self.visible = false; + self.tooltip_text = "Unknown" + App.closeWindow("media") + } + }) + + return button +} + + +function KeyboardLayout() { + const widget = Widget.Label({ + class_name: "keyboard", + label: keyboard_layout.bind() + }) + return widget +} + + +function OpenSideBar() { + const button = Widget.Button({ + class_name: "filled_tonal_button awesome_icon", + on_clicked: () => { + App.toggleWindow("sidebar") + // Utils.execAsync(["ags", "-t", "sidebar"]) + }, + label: "" + }) + + return button +} + +function TaskBar() { + let globalWidgets: Button, any>[] = []; + + function Clients(clients: Client[]) { + const currentClientIds = clients.map(client => client.pid); + globalWidgets = globalWidgets.filter(widget => currentClientIds.includes(widget.attribute.pid)); + + clients.forEach(item => { + let widget = globalWidgets.find(w => w.attribute.pid === item.pid); + //if (item.class == "kitty") { + // return; + //} + if (widget) { + widget.tooltip_markup = item.title; + } else { + let icon: string | undefined; + if (item.class == "com.github.Aylur.ags") { + if (item.initialTitle == "Settings") { + icon = "emblem-system-symbolic" + } + } + else + icon = getIconNameFromClass(item.class) + widget = Widget.Button({ + attribute: { pid: item.pid }, + child: Widget.Icon({ icon: icon }), + tooltip_markup: item.title, + }); + globalWidgets.push(widget); + } + }); + return globalWidgets; + } + + return Widget.Box({ + class_name: "tray", + spacing: 5, + children: hyprland.bind("clients").as(Clients), + }) +} + +function volumeIndicator() { + return Widget.EventBox({ + onScrollUp: () => audio.speaker.volume += 0.01, + onScrollDown: () => audio.speaker.volume -= 0.01, + class_name: "filled_tonal_button volume_box", + child: Widget.Button({ + on_primary_click: () => Utils.execAsync("pavucontrol").catch(print), + on_secondary_click: () => audio.speaker.is_muted = !audio.speaker.is_muted, + child: Widget.Box({ + children: [ + Widget.Icon().hook(audio.speaker, self => { + const vol = audio.speaker.volume * 100; + const icon = [ + [101, 'overamplified'], + [67, 'high'], + [34, 'medium'], + [1, 'low'], + [0, 'muted'], + ].find(([threshold]) => Number(threshold) <= vol)?.[1]; + if (audio.speaker.is_muted) + self.icon = `audio-volume-muted-symbolic`; + else + self.icon = `audio-volume-${icon}-symbolic`; + self.tooltip_text = `Volume ${Math.floor(vol)}%`; + }), + Widget.Label({ + label: audio.speaker.bind("volume").as(volume => `${Math.floor(volume * 100)}%`), + }) + ] + }) + + }) + }) +} + + +function Left() { + return Widget.Box({ + // margin_left: 15, + class_name: "modules-left", + hpack: "start", + spacing: 8, + children: [ + AppLauncher(), + MediaPlayer(), + TaskBar() + ], + }) +} + + +function Center() { + return Widget.Box({ + class_name: "modules-center", + hpack: "center", + spacing: 8, + children: [ + Workspaces(), + ], + }) +} + + +function Right() { + return Widget.Box({ + // margin_right: 15, + class_name: "modules-right", + hpack: "end", + spacing: 8, + children: [ + volumeIndicator(), + KeyboardLayout(), + BatteryLabel(), + SysTray(), + Wifi(), + Clock(), + OpenSideBar() + ], + }) +} + + +export const Bar = async (monitor = 0) => { + return Widget.Window({ + name: `bar-${monitor}`, + class_name: "bar", + monitor, + //anchor: ["top", "left", "right"], + anchor: ["bottom", "left", "right"], + exclusivity: "exclusive", + child: Widget.CenterBox({ + start_widget: Left(), + center_widget: Center(), + end_widget: Right(), + }), + + }) +} + +export const BarCornerTopLeft = (monitor = 0) => Widget.Window({ + monitor, + name: `bar_corner_tl${monitor}`, + class_name: "transparent", + layer: 'top', + anchor: ['top', 'left'], + exclusivity: 'normal', + visible: true, + child: RoundedCorner('top_left', { className: 'corner', }), + setup: enableClickThrough, +}); + +export const BarCornerTopRight = (monitor = 0) => Widget.Window({ + monitor, + name: `bar_corner_tr${monitor}`, + class_name: "transparent", + layer: 'top', + anchor: ['top', 'right'], + exclusivity: 'normal', + visible: true, + child: RoundedCorner('top_right', { className: 'corner', }), + setup: enableClickThrough, +}); + diff --git a/config/ags/modules/cliphist.ts b/config/ags/modules/cliphist.ts new file mode 100644 index 00000000..36729711 --- /dev/null +++ b/config/ags/modules/cliphist.ts @@ -0,0 +1,127 @@ +const { GLib } = imports.gi; +const WINDOW_NAME = "cliphist" +import popupwindow from './misc/popupwindow.ts'; +import Box from 'types/widgets/box.js'; +const { Gtk } = imports.gi; + +type EntryObject = { + id: string; + content: string; + entry: string; +}; + +function ClipHistItem(entry: string) { + let [id, ...content] = entry.split('\t'); + let clickCount = 0; + let button = Widget.Button({ + class_name: "entry_container", + child: Widget.Label({ + label: entry, + class_name: "entry_label", + xalign: 0, + vpack: "center", + truncate: "end", + }) + }); + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 1) { + App.closeWindow(WINDOW_NAME); + Utils.execAsync(`${App.configDir}/scripts/cliphist.sh --copy-by-id ${id}`); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return Widget.Box({ + attribute: { content: content.join(' ').trim() }, + orientation: Gtk.Orientation.VERTICAL, + children: [ + button, + Widget.Separator({ + class_name: "entry_divider", + orientation: Gtk.Orientation.HORIZONTAL, + }), + ], + }); +} + +function ClipHistWidget({ width = 500, height = 500, spacing = 12 }) { + let output: string; + let entries: string[]; + let clipHistItems: EntryObject[]; + let widgets: Box[]; + + const list = Widget.Box({ + vertical: true, + spacing, + }); + + async function repopulate() { + output = await Utils.execAsync(`${App.configDir}/scripts/cliphist.sh --get`) + .then(str => str) + .catch(err => { + print(err); + return ""; + }); + entries = output.split('\n').filter(line => line.trim() !== ''); + clipHistItems = entries.map(entry => { + let [id, ...content] = entry.split('\t'); + return { id: id.trim(), content: content.join(' ').trim(), entry: entry }; + }); + widgets = clipHistItems.map(item => ClipHistItem(item.entry)); + list.children = widgets; + } + repopulate(); + + const entry = Widget.Entry({ + hexpand: true, + class_name: "cliphistory_entry", + placeholder_text: "Search", + on_change: ({ text }) => { + const lowerCaseText = (text ?? "").toLowerCase(); + widgets.forEach(item => { + item.visible = item.attribute.content.toLowerCase().includes(lowerCaseText); + }); + }, + }); + + return Widget.Box({ + vertical: true, + class_name: "cliphistory_box", + margin_top: 14, + margin_right: 14, + children: [ + entry, + Widget.Scrollable({ + hscroll: "never", + css: `min-width: ${width}px; min-height: ${height}px;`, + child: list, + }), + ], + setup: self => self.hook(App, (_, windowName, visible) => { + if (windowName !== WINDOW_NAME) return; + if (visible) { + repopulate(); + entry.text = ""; + } + }), + }); +} + +export const cliphist = popupwindow({ + name: WINDOW_NAME, + class_name: "cliphistory", + visible: false, + keymode: "exclusive", + child: ClipHistWidget({ + width: 500, + height: 500, + spacing: 0, + }), + anchor: ["bottom", "right"], +}); diff --git a/config/ags/modules/media.ts b/config/ags/modules/media.ts new file mode 100644 index 00000000..51640ea4 --- /dev/null +++ b/config/ags/modules/media.ts @@ -0,0 +1,172 @@ +import { MprisPlayer } from 'types/service/mpris.js'; +import popupwindow from './misc/popupwindow.ts'; +import Label from 'types/widgets/label.js'; +const mpris = await Service.import("mpris") +const players = mpris.bind("players") + +const FALLBACK_ICON = "audio-x-generic-symbolic" +const PLAY_ICON = "media-playback-start-symbolic" +const PAUSE_ICON = "media-playback-pause-symbolic" +const PREV_ICON = "media-skip-backward-symbolic" +const NEXT_ICON = "media-skip-forward-symbolic" +const WINDOW_NAME = "media" + +function lengthStr(length: number): string { + const min = Math.floor(length / 60) + const sec = Math.floor(length % 60) + const sec0 = sec < 10 ? "0" : "" + return `${min}:${sec0}${sec}` +} + +function Player(player: MprisPlayer) { + const img = Widget.Box({ + class_name: "img", + vpack: "start", + css: player.bind("cover_path").transform(p => ` + background-image: url('${p}'); + `), + }) + + const title = Widget.Label({ + class_name: "title", + wrap: true, + hpack: "start", + label: player.bind("track_title"), + }) + + const artist = Widget.Label({ + class_name: "artist", + wrap: true, + hpack: "start", + label: player.bind("track_artists").transform(a => a.join(", ")), + }) + + const positionSlider = Widget.Slider({ + class_name: "position", + draw_value: false, + on_change: ({ value }) => player.position = value * player.length, + visible: player.bind("length").as(l => l > 0), + setup: self => { + function update() { + const value = player.position / player.length + self.value = value > 0 ? value : 0 + } + self.hook(player, update) + self.hook(player, update, "position") + self.poll(1000, update) + }, + }) + + const positionLabel = Widget.Label({ + class_name: "position", + hpack: "start", + setup: self => { + const update = (self: Label) => { + self.label = lengthStr(player.position) + self.visible = player.length > 0 + } + + self.hook(player, update, "position") + self.poll(1000, update) + }, + }) + + const lengthLabel = Widget.Label({ + class_name: "length", + hpack: "end", + visible: player.bind("length").transform(l => l > 0), + label: player.bind("length").transform(lengthStr), + }) + + const icon = Widget.Icon({ + class_name: "icon", + hexpand: true, + hpack: "end", + vpack: "start", + tooltip_text: player.identity || "", + icon: player.bind("entry").transform(entry => { + const name = `${entry}-symbolic` + return Utils.lookUpIcon(name) ? name : FALLBACK_ICON + }), + }) + + const playPause = Widget.Button({ + class_name: "play-pause", + on_clicked: () => player.playPause(), + visible: player.bind("can_play"), + child: Widget.Icon({ + icon: player.bind("play_back_status").transform(s => { + switch (s) { + case "Playing": return PAUSE_ICON + case "Paused": + case "Stopped": return PLAY_ICON + } + }), + }), + }) + + const prev = Widget.Button({ + on_clicked: () => player.previous(), + visible: player.bind("can_go_prev"), + child: Widget.Icon(PREV_ICON), + }) + + const next = Widget.Button({ + on_clicked: () => player.next(), + visible: player.bind("can_go_next"), + child: Widget.Icon(NEXT_ICON), + }) + + return Widget.Box( + { + class_name: "player", + margin_left: 14, + margin_top: 14, + }, + img, + Widget.Box( + { + vertical: true, + hexpand: true, + }, + Widget.Box([ + title, + icon, + ]), + artist, + Widget.Box({ vexpand: true }), + positionSlider, + Widget.CenterBox({ + start_widget: positionLabel, + center_widget: Widget.Box({ + class_name: "player_buttons", + children: [ + prev, + playPause, + next, + ] + }), + end_widget: lengthLabel, + }), + ), + ) +} + +export function Media() { + return Widget.Box({ + vertical: true, + css: "min-height: 2px; min-width: 2px;", + visible: players.as(p => p.length > 0), + children: players.as(p => p.map(Player)), + }) +} + +export const media = popupwindow({ + name: WINDOW_NAME, + class_name: "player_window", + visible: false, + keymode: "exclusive", + child: Media(), + //anchor: ["left", "top"], + anchor: ["left", "bottom"], +}) diff --git a/config/ags/modules/misc/Dock.js b/config/ags/modules/misc/Dock.js new file mode 100644 index 00000000..62489b59 --- /dev/null +++ b/config/ags/modules/misc/Dock.js @@ -0,0 +1,114 @@ +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; + + +const prefix = "100" // Identifier for minimized workspace + +function getMinimizedWS(maximizedWS){ + return parseInt(prefix + maximizedWS) +} + +function getMaximizedWS(minimizedWS){ + return parseInt(minimizedWS.toString().substring(prefix.length)) +} + +function isMinimized(ws){ + ws = ws.toString() + if (ws.length > 3 || ws.slice(0, prefix.length) == prefix){ + return true + } + else{ + return false + } +} + + +const focusClient = (client) => { + + // If minimized + if (isMinimized(client.workspace.id)){ + var maximizedWS = getMaximizedWS(client.workspace.id) + Hyprland.messageAsync(`dispatch movetoworkspacesilent ${maximizedWS},address:${client.address}`) + // Focus window + //Hyprland.messageAsync(`dispatch focuswindow address:${client.address}`) + Hyprland.messageAsync(`dispatch alterzorder top,address:${client.address}`) + } + + // If maximized + else{ + var minimizedWS = getMinimizedWS(client.workspace.id) + Hyprland.messageAsync(`dispatch movetoworkspacesilent ${minimizedWS},address:${client.address}`) + } + +} + +const Client = (client = null) => Widget.Box({ + // Attributes + attribute: { + returnWS: client.workspace, + }, +}) + + +const appButton = (client = null) => Widget.Button({ + class_name: "dock-button", + tooltip_text: client.title, + on_primary_click: () => focusClient(client), + child: Widget.Box({ + vertical: true, + children: [ + Widget.Box({ + children: [ + Widget.Box({ + class_name: "dock-app-indicator", + vpack: "center", + setup: (self) => { + self.hook(Hyprland, () => { + //self.toggleClassName("dock-button-current", Hyprland.active.client.address === client.address) + self.toggleClassName("dock-app-indicator-active", Hyprland.active.client.address === client.address) + }, 'event') + } + }), + /* + Widget.Icon({ + class_name: 'client-icon', + css: 'font-size: 3rem;', + icon: client.class, + }), + */ + ], + }), + Widget.Label({ + label: client.class, + truncate: 'end', + maxWidthChars: 8, + }) + ], + }), +}); + +const clientList = Widget.Scrollable({ + hscroll: "never", + child: Widget.Box({ + class_name: "dock-container", + css: "min-height: 6rem;", + css: "min-width: 6rem;", + vertical: true, + }).hook(Hyprland, self => { + //check if ws is empty + self.children = Hyprland.clients.filter(client => client.class != "" && (client.workspace.id === Hyprland.active.workspace.id || client.workspace.id === getMinimizedWS(Hyprland.active.workspace.id))).map(client => { + return appButton(client) + }) + }) +}) + +export const Dock = (monitor = 0) => Widget.Window({ + name: `Dock`, // name has to be unique + monitor, + visible: false, + //margins: [4,64,4,64], + //margins: [8,8,8,8], + anchor: ['bottom', 'left', 'top'], + exclusivity: 'exclusive', + child: clientList, +}); diff --git a/config/ags/modules/misc/cairo_roundedcorner.js b/config/ags/modules/misc/cairo_roundedcorner.js new file mode 100644 index 00000000..20571a3d --- /dev/null +++ b/config/ags/modules/misc/cairo_roundedcorner.js @@ -0,0 +1,51 @@ +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +const { Gtk } = imports.gi; +const Lang = imports.lang; + +export const RoundedCorner = (place, props) => Widget.DrawingArea({ + ...props, + hpack: place.includes('left') ? 'start' : 'end', + vpack: place.includes('top') ? 'start' : 'end', + setup: (widget) => Utils.timeout(1, () => { + const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL); + const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL); + widget.set_size_request(r, r); + // @ts-ignore + widget.connect('draw', Lang.bind(widget, (widget, cr) => { + const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL); + const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL); + // const borderColor = widget.get_style_context().get_property('color', Gtk.StateFlags.NORMAL); + // const borderWidth = widget.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway + widget.set_size_request(r, r); + + switch (place) { + case 'top_left': + cr.arc(r, r, r, Math.PI, 3 * Math.PI / 2); + cr.lineTo(0, 0); + break; + + case 'top_right': + cr.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI); + cr.lineTo(r, 0); + break; + + case 'bottom_left': + cr.arc(r, 0, r, Math.PI / 2, Math.PI); + cr.lineTo(0, r); + break; + + case 'bottom_right': + cr.arc(0, 0, r, 0, Math.PI / 2); + cr.lineTo(r, r); + break; + } + + cr.closePath(); + cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha); + cr.fill(); + // cr.setLineWidth(borderWidth); + // cr.setSourceRGBA(borderColor.red, borderColor.green, borderColor.blue, borderColor.alpha); + // cr.stroke(); + })); + }), +}); \ No newline at end of file diff --git a/config/ags/modules/misc/clickthrough.js b/config/ags/modules/misc/clickthrough.js new file mode 100644 index 00000000..e4592f11 --- /dev/null +++ b/config/ags/modules/misc/clickthrough.js @@ -0,0 +1,4 @@ +import Cairo from 'gi://cairo?version=1.0'; + +export const dummyRegion = new Cairo.Region(); +export const enableClickThrough = (self) => self.input_shape_combine_region(dummyRegion); \ No newline at end of file diff --git a/config/ags/modules/misc/popupwindow.ts b/config/ags/modules/misc/popupwindow.ts new file mode 100644 index 00000000..c30c6c2f --- /dev/null +++ b/config/ags/modules/misc/popupwindow.ts @@ -0,0 +1,44 @@ +import App from 'resource:///com/github/Aylur/ags/app.js'; +import Widget from 'resource:///com/github/Aylur/ags/widget.js'; +import { WindowProps, Window } from 'types/widgets/window'; +const { Gtk, GLib } = imports.gi; + +type _WindowProps = WindowProps> | undefined[]; + +type Type = { + name: string, + child: any, + showClassName?: string, + hideClassName?: string, +} + +export default ({ + name, + child, + showClassName = "", + hideClassName = "", + ...props +}: T & Omit<_WindowProps, keyof Type>) => { + return Widget.Window({ + name, + visible: false, + type: Gtk.WindowType.POPUP, + layer: 'overlay', + resizable: true, + ...props, + setup: (self) => { + self.keybind("Escape", () => App.closeWindow(name)); + if (showClassName != "" && hideClassName !== "") { + self.hook(App, (self, currentName, visible) => { + if (currentName === name) { + self.toggleClassName(hideClassName, !visible); + } + }); + + if (showClassName !== "" && hideClassName !== "") + self.class_name = `${showClassName} ${hideClassName}`; + } + }, + child: child, + }); +} diff --git a/config/ags/modules/notificationPopups.ts b/config/ags/modules/notificationPopups.ts new file mode 100644 index 00000000..5be0241d --- /dev/null +++ b/config/ags/modules/notificationPopups.ts @@ -0,0 +1,257 @@ +import { Gtk as GtkType } from "types/@girs/gtk-3.0/gtk-3.0"; +import { Notification as NotificationType } from "types/service/notifications"; +import Box from "types/widgets/box"; +import { timeout } from "resource:///com/github/Aylur/ags/utils.js"; +import GLib from "gi://GLib"; +import Pango from "gi://Pango"; +import Label from "types/widgets/label"; + +const notifications = await Service.import("notifications") +const { Gtk } = imports.gi; + +function NotificationIcon({ app_entry, app_icon, image }: NotificationType): Box { + if (image) { + return Widget.Box({ + css: `background-image: url("${image}");` + + "background-size: contain;" + + "background-repeat: no-repeat;" + + "background-position: center;", + }) + } + + let icon = "dialog-information-symbolic" + if (Utils.lookUpIcon(app_icon)) + icon = app_icon + + if (app_entry && Utils.lookUpIcon(app_entry)) + icon = app_entry + + return Widget.Box({ + child: Widget.Icon(icon), + }) +} + + +export const Notification = (notification: NotificationType, dismiss = true) => Widget.Box({ + class_name: `notification ${notification.urgency}`, + vertical: true, + children: [ + Widget.EventBox({ + on_primary_click: (box) => { + // @ts-ignore + const label: Label = box.child.children[1].children[1]; + if (label.lines < 0) { + label.lines = 3; + label.truncate = "end"; + } else { + label.lines = -1; + label.truncate = "none"; + } + }, + child: Widget.Box({ + children: [ + Widget.Box({ + class_name: "notification-icon", + child: NotificationIcon(notification), + vpack: "start" + }), + Widget.Box({ + vertical: true, + children: [ + Widget.Box({ + children: [ + Widget.Label({ + class_name: "notification-title", + label: notification.summary, + justification: "left", + max_width_chars: 3, + truncate: "end", + lines: 1, + xalign: 0, + hexpand: true, + }), + Widget.Label({ + class_name: "notification-time", + label: GLib.DateTime.new_from_unix_local(notification.time).format("%I:%M %p"), + }), + Widget.Button({ + class_name: "standard_icon_button", + child: Widget.Icon("window-close-symbolic"), + on_clicked: () => { + if (dismiss) { + notification.dismiss(); + } + else { + notification.close(); + } + }, + css: "margin-left: 5px;" + }) + ] + }), + Widget.Label({ + class_name: "notification-body", + justification: "left", + max_width_chars: 24, + lines: 3, + truncate: "end", + wrap_mode: Pango.WrapMode.WORD_CHAR, + xalign: 0, + wrap: true, + // HACK: remove linebreaks, so lines property works properly + label: notification.body.replace(/(\r\n|\n|\r)/gm, " "), + }), + notification.hints.value ? + Widget.ProgressBar({ + class_name: "notification-progress", + value: Number(notification.hints.value.unpack()) / 100 + }) : Widget.Box() + ] + }) + ] + }) + }), + Widget.Box({ + halign: Gtk.Align.END, + class_name: "notification-actions", + children: notification.actions.map(action => Widget.Button({ + child: Widget.Label(action.label), + on_clicked: () => notification.invoke(action.id), + class_name: "notification-action-button", + })) + }) + ] +}); + +const NotificationReveal = (notification: NotificationType, visible = false, dismiss = true) => { + const transition_duration = 200; + const secondRevealer = Widget.Revealer({ + vpack: "start", + child: Notification(notification, dismiss), + reveal_child: visible, + transition: "slide_left", + transition_duration: transition_duration, + hexpand: true, + class_name: "second_revealer", + setup: (revealer) => { + timeout(1, () => { + revealer.reveal_child = true; + }); + }, + }); + + const firstRevealer = Widget.Revealer({ + child: secondRevealer, + reveal_child: true, + transition: "slide_down", + transition_duration: transition_duration, + class_name: "first_revealer" + }); + + type BoxAttrs = { + destroyWithAnims: any, + count: number, + id: number, + } + + let box: Box; + + const destroyWithAnims = () => { + secondRevealer.reveal_child = false; + timeout(transition_duration, () => { + firstRevealer.reveal_child = false; + timeout(transition_duration, () => { + box.destroy(); + }); + }); + }; + box = Widget.Box({ + hexpand: true, + hpack: "end", + attribute: { + "destroyWithAnims": destroyWithAnims, + count: 0, + id: notification.id, + }, + children: [firstRevealer], + }); + return box; +}; + +type NotificationsBoxType = { + exclude: string[], + include: string[] +} + +export function NotificationPopups( + dismiss = true, + { exclude, include }: NotificationsBoxType = { exclude: [], include: [] }, + timeout = true, + revealer = NotificationReveal +) { + const list = Widget.Box({ + vpack: "start", + vertical: true, + children: notifications.popups.map(id => revealer(id, false, dismiss)), + }) + + function onNotified(_: any, id: number) { + const n = notifications.getNotification(id) + if (notifications.dnd || !n) + return; + if (exclude.includes(n.app_name.trim())) + return + if (!include.includes(n.app_name.trim()) && include.length > 0) + return + const original = list.children.find(n => n.attribute.id === id); + const replace = original?.attribute.id; + if (!replace) { + const notification = revealer(n, false, dismiss); + notification.attribute.count = 1; + list.pack_end(notification, false, false, 0) + } + else if (original) { + const notification = revealer(n, true, dismiss); + notification.attribute.count++; + original.destroy() + list.pack_end(notification, false, false, 0) + } + if (timeout) + setTimeout(() => { + onDismissed(_, id) + }, 5000) + } + + function onDismissed(_: any, id: number) { + const original = list.children.find(n => n.attribute.id === id); + if (!original) + return + original.attribute.count--; + if (original.attribute.count <= 0) { + original.attribute.destroyWithAnims() + } + } + + list.hook(notifications, onNotified, "notified") + .hook(notifications, onDismissed, dismiss ? "dismissed" : "closed") + return list +} + +export function Notifications(monitor = 0) { + const window = Widget.Window({ + monitor, + name: `notifications${monitor}`, + class_name: "notification-popups", + anchor: ["bottom", "right"], + type: Gtk.WindowType.POPUP, + child: Widget.Box({ + css: "min-width: 2px; min-height: 2px;", + class_name: "notifications", + hexpand: true, + vexpand: true, + child: NotificationPopups(), + }), + visible: true, + }) + return window +} diff --git a/config/ags/modules/sidebar/buttons.ts b/config/ags/modules/sidebar/buttons.ts new file mode 100644 index 00000000..ec8a5c2e --- /dev/null +++ b/config/ags/modules/sidebar/buttons.ts @@ -0,0 +1,178 @@ +const { Gtk, GLib } = imports.gi; +const lock_command = `hyprlock`; +const logout_command = `loginctl kill-session $XDG_SESSION_ID`; +const shutdown_command = `systemctl poweroff`; +const reboot_command = `systemctl reboot`; +const suspend_command = `systemctl suspend`; + +function LockButton({ icon, ...props }) { + let clickCount = 0; + let button = Widget.Button({ + tooltip_text: "Lock", + child: Widget.Label({ + label: icon, + class_name: "awesome_icon" + }), + class_name: "outline_button", + ...props, + }) + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 2) { + Utils.execAsync(lock_command).catch(print); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return button +} + + +function SuspendButton({ icon, ...props }) { + let clickCount = 0; + let button = Widget.Button({ + tooltip_text: "Suspend", + child: Widget.Label({ + label: icon, + class_name: "awesome_icon" + }), + class_name: "outline_button", + ...props, + }) + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 2) { + Utils.execAsync(`mpc -q pause`).catch(); + Utils.execAsync(`playerctl pause`).catch(); + Utils.execAsync(suspend_command).catch(); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return button +} + + +function LogoutButton({ icon, ...props }) { + let clickCount = 0; + let button = Widget.Button({ + tooltip_text: "Logout", + child: Widget.Label({ + label: icon, + class_name: "awesome_icon" + }), + class_name: "outline_button", + ...props, + }) + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 2) { + Utils.execAsync(logout_command).catch(); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return button +} + + +function RebootButton({ icon, ...props }) { + let clickCount = 0; + let button = Widget.Button({ + tooltip_text: "Reboot", + child: Widget.Label({ + label: icon, + class_name: "awesome_icon" + }), + class_name: "outline_button", + ...props, + }) + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 2) { + Utils.execAsync(reboot_command).catch(); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return button +} + + +function ShutdownButton({ icon, ...props }) { + let clickCount = 0; + let button = Widget.Button({ + tooltip_text: "Shutdown", + child: Widget.Label({ + label: icon, + class_name: "awesome_icon" + }), + class_name: "outline_button", + ...props, + }) + + button.connect('clicked', () => { + clickCount++; + if (clickCount === 2) { + Utils.execAsync(shutdown_command).catch(); + clickCount = 0; + } + }); + + button.connect('focus-out-event', () => { + clickCount = 0; + }); + + return button +} + + +export function Buttons() { + return Widget.Box({ + class_name: "sidebar_buttons", + hexpand: true, + spacing: 5, + children: [ + LockButton({ + icon: "", + hexpand: true, + }), + SuspendButton({ + icon: "", + hexpand: true, + }), + LogoutButton({ + icon: "", + hexpand: true, + }), + RebootButton({ + icon: "", + hexpand: true, + }), + ShutdownButton({ + icon: "", + hexpand: true, + }) + ] + }) +} diff --git a/config/ags/modules/sidebar/main.ts b/config/ags/modules/sidebar/main.ts new file mode 100644 index 00000000..a790f517 --- /dev/null +++ b/config/ags/modules/sidebar/main.ts @@ -0,0 +1,16 @@ +import popupwindow from '../misc/popupwindow.js'; +import { SideBar } from './sidebar.ts' + +export const WINDOW_NAME = "sidebar" + + +export const sidebar = popupwindow({ + name: WINDOW_NAME, + + class_name: "sidebar", + visible: false, + keymode: "exclusive", + child: SideBar(), + anchor: ["top", "right", "bottom"], + css: "min-width: 443px;" +}) diff --git a/config/ags/modules/sidebar/management.ts b/config/ags/modules/sidebar/management.ts new file mode 100644 index 00000000..5723037c --- /dev/null +++ b/config/ags/modules/sidebar/management.ts @@ -0,0 +1,387 @@ + +const notifications = await Service.import("notifications") +const network = await Service.import('network') +import { OpenSettings } from "apps/settings/main.ts"; +import { WINDOW_NAME } from "./main.ts" + +const { Gtk } = imports.gi; +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; + +const idle_inhibitor = Variable(false); +const night_light = Variable(false); +const screen_recorder = Variable(false); +const currentPage = Variable(0); +export const bluetooth_enabled = Variable('off', { + poll: [1000, `${App.configDir}/scripts/bluetooth.sh --get`] +}) + +const powerProfiles = await Service.import('powerprofiles'); +const icons = { + 'performance': ' ', + 'balanced': ' ', + 'power-saver': '󰡵 ' +}; + +function WifiIndicator() { + return Widget.Box({ + css: "padding-left: 15px; padding-right: 15px; padding-top: 5px; padding-bottom: 5px;", + children: [ + Widget.Label({ + label: "\udb82\udd28", + class_name: "awesome_icon", + css: `font-weight: bold; font-size: 20px; margin-right: 0.60em;`, + }), + Widget.Box({ + visible: network.wifi.bind('enabled'), + orientation: Gtk.Orientation.VERTICAL, + children: [ + Widget.Box([ + Widget.Label({ + label: "Internet", + }), + ]), + Widget.Label({ + label: network.wifi.bind('ssid') + .as(ssid => ssid || 'Unknown'), + class_name: "ssid", + xalign: 0, + vpack: "center", + truncate: "end", + }), + ] + }), + Widget.Label({ + visible: network.wifi.bind('enabled').as(enabled => !enabled), + label: "Internet", + }), + Widget.Box({ + halign: Gtk.Align.END, + hexpand: true, + child: Widget.Label({ + label: "", + class_name: "awesome_icon", + css: `font-weight: normal; font-size: 15px;`, + }) + }) + ], + }) +} + +const WiredIndicator = () => Widget.Box({ + css: "padding-left: 15px; padding-right: 15px; padding-top: 5px; padding-bottom: 5px;", + children: [ + Widget.Icon({ + icon: network.wired.bind('icon_name'), + }), + Widget.Label({ + label: "Internet", + }), + ] +}) + + +const NetworkIndicator = () => Widget.Stack({ + children: { + wifi: WifiIndicator(), + wired: WiredIndicator(), + }, + shown: network.bind('primary').as(p => p || 'wifi'), +}) + + +function IconAndName({ label, icon, padding = "0.3em", arrow = false }) { + let box = Widget.Box({ + css: "padding-left: 15px; padding-right: 15px; padding-top: 5px; padding-bottom: 5px;", + children: [ + Widget.Label({ + label: icon, + class_name: "awesome_icon", + css: `font-weight: bold; font-size: 20px; margin-right: ${padding};`, + }), + Widget.Label({ + label: label, + justification: "center", + }), + ] + }) + if (arrow) { + const arrow = Widget.Box({ + halign: Gtk.Align.END, + hexpand: true, + child: Widget.Label({ + label: "", + class_name: "awesome_icon", + css: `font-weight: normal; font-size: 15px;`, + }) + }) + // @ts-ignore + box.children = [...box.children, arrow] + } + return box +} + +function isScreenRecordingOn() { + // Check if wf-recorder is running + // Bash command outputs 0 if yes or 1 if no + let state = Utils.execAsync('bash -c "pidof wf-recorder > /dev/null; echo $?"') + if (state == "0"){ + return true + } + else{ + return false + } +} + +function Page1() { + return Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 5, + hexpand: true, + class_name: "management_box", + children: [ + Widget.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + hexpand: true, + spacing: 2.5, + children: [ + Widget.Button({ + hexpand: true, + class_name: network.wifi.bind("enabled") + .as(enabled => enabled ? "management_button active" : "management_button"), + child: NetworkIndicator(), + on_primary_click: () => { + network.toggleWifi(); + }, + on_secondary_click: () => { + App.closeWindow(WINDOW_NAME); + App.openWindow("network"); + } + }), + Widget.Button({ + hexpand: true, + class_name: bluetooth_enabled.bind() + .as(state => state.trim() == "yes" ? "management_button active" : "management_button" + ), + child: IconAndName({ + label: "Bluetooth", + icon: "󰂯", + arrow: true, + }), + on_primary_click: () => { + Utils.execAsync(`${App.configDir}/scripts/bluetooth.sh --toggle`) + .then(out => { bluetooth_enabled.setValue(out) }) + }, + on_secondary_click: () => { + Utils.execAsync("blueman-manager") + App.closeWindow(WINDOW_NAME) + } + }) + ] + }), + Widget.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 2.5, + hexpand: true, + children: [ + Widget.Button({ + hexpand: true, + class_name: idle_inhibitor.bind() + .as(bool => bool ? "management_button active" : "management_button"), + child: IconAndName({ + label: "Idle inhibitor", + icon: "" + }), + onClicked: () => { + idle_inhibitor.setValue(!idle_inhibitor.value) + if (idle_inhibitor.value) Utils.execAsync(['bash', '-c', `pidof wayland-idle-inhibitor.py || ${App.configDir}/scripts/wayland-idle-inhibitor.py`]).catch(print) + else Utils.execAsync('pkill -f wayland-idle-inhibitor.py').catch(print); + }, + setup: () => { + idle_inhibitor.setValue(!!Utils.exec('pidof wayland-idle-inhibitor.py')); + }, + }), + Widget.Button({ + hexpand: true, + class_name: notifications.bind("dnd").as((bool) => { + return bool ? "management_button active" : "management_button"; + }), + on_clicked: () => { + notifications.dnd = notifications.dnd ? false : true + }, + child: IconAndName({ + label: "Do Not Disturb", + icon: "" + }) + }) + ] + }), + Widget.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 2.5, + hexpand: true, + children: [ + Widget.Button({ + hexpand: true, + class_name: screen_recorder.bind() + .as(bool => bool ? "management_button active" : "management_button"), + on_clicked: (self) => { + screen_recorder.setValue(!screen_recorder.value) + // Adjust indicator + let isRecording = isScreenRecordingOn() + self.toggleClassName("active-button", !isRecording) // Toggles active indicator + self.toggleClassName("recording", !isRecording) // Toggles active indicator + + // Starts screen recorder if not running + // Stops screen recorder if running + Utils.execAsync(['bash', '-c', 'mkdir ~/Videos/Screenrecordings; pkill wf-recorder; if [ $? -ne 0 ]; then wf-recorder -f ~/Videos/Screenrecordings/recording_"$(date +\'%b-%d-%Y-%I:%M:%S-%P\')".mp4 -g "$(slurp)" --pixel-format yuv420p; fi']).catch(logError); + }, + child: IconAndName({ + label: "Screen Recorder", + icon: "", + setup: self=>{} + }) + }), + + Widget.Button({ + hexpand: true, + class_name: night_light.bind() + .as(mode => mode ? "management_button active" : "management_button"), + child: IconAndName({ + label: "Night Light", + icon: "" + }), + onClicked: () => { + night_light.setValue(!night_light.value) + Utils.execAsync(`${App.configDir}/scripts/night-light.sh --toggle`) + .then(out => { + if (out.trim() == "enabled") night_light.setValue(true) + else if (out.trim() == "disabled") night_light.setValue(false) + }) + .catch(err => { + night_light.setValue(!night_light.value); + }); + }, + setup: () => { + Utils.execAsync(`${App.configDir}/scripts/night-light.sh --get`) + .then(out => { + if (out.trim() == "enabled") night_light.setValue(true) + else if (out.trim() == "disabled") night_light.setValue(false) + }) + .catch(print); + } + }) + ] + }) + ] + }) +} + + +function Page2() { + return Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 5, + hexpand: true, + class_name: "management_box", + children: [ + Widget.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 2.5, + children: [ + Widget.Button({ + hexpand: true, + class_name: "management_button", + child: IconAndName({ + label: "Color picker", + icon: "", + arrow: true, + }), + on_primary_click: () => { + App.closeWindow(WINDOW_NAME); + Utils.execAsync("sleep 0.5") + .then(() => + Utils.execAsync("hyprpicker -a").catch(print) + ) + .catch(print); + } + }), + Widget.Button({ + hexpand: true, + class_name: "management_button", + child: Widget.Box({ + children: [ + Widget.Label({ + label: powerProfiles.bind('active_profile').as(x => icons[x]) + }), + Widget.Label({ + label: powerProfiles.bind('active_profile').as(x => x.toUpperCase()) + }) + ] + }), + on_clicked: () => { + switch (powerProfiles.active_profile) { + case 'balanced': + powerProfiles.active_profile = 'performance'; + break; + case 'power-saver': + powerProfiles.active_profile = 'balanced'; + break; + default: + powerProfiles.active_profile = 'power-saver'; + break; + }; + }, + }), + ] + }) + ] + }) +} + +const createDotButton = (index: number) => Widget.Button({ + label: '', + onClicked: () => currentPage.setValue(index), + class_name: currentPage.bind().as(v => v == index ? "dotbutton active" : "dotbutton"), + hexpand: false, +}); + + +export function Management() { + let pages = { + "page1": Page1(), + "page2": Page2() + } + const numberOfPages = Object.keys(pages).length; + const pageNames = Array.from({ length: numberOfPages }, (_, i) => `page${i + 1}`); + + const stack = Widget.Stack({ + children: pages, + // @ts-ignore + shown: currentPage.bind().as(v => `page${v + 1}`), + transition: "slide_left_right", + transitionDuration: 200, + }) + const dotButtons = pageNames.map((_, index) => createDotButton(index)); + return Widget.EventBox({ + onScrollUp: () => currentPage.setValue((currentPage.value + 1) % numberOfPages), + onScrollDown: () => { + if (currentPage.value - 1) { + currentPage.setValue(numberOfPages - 1) + return + } + currentPage.setValue(currentPage.value - 1); + }, + child: Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + children: [ + stack, + Widget.Box({ + children: dotButtons, + class_name: "dotbuttons_box", + halign: Gtk.Align.CENTER, + }) + ] + }) + }) +} diff --git a/config/ags/modules/sidebar/navigation.ts b/config/ags/modules/sidebar/navigation.ts new file mode 100644 index 00000000..4281ab05 --- /dev/null +++ b/config/ags/modules/sidebar/navigation.ts @@ -0,0 +1,88 @@ +const { Gtk } = imports.gi; +import { NotificationsBox } from "./notifications.ts" +import { SystemBox } from "./system.ts" +let shown = Variable("Messages"); + + +type ButtonType = { + page: string, + label: string, + icon: string +} + + +function Button({ page, label, icon }: ButtonType) { + return Widget.Button({ + class_name: shown.bind().as(_page => _page == page ? "navigation_button active" : "navigation_button"), + hexpand: true, + child: Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "container_outer", + children: [ + Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + halign: Gtk.Align.CENTER, + class_name: "container", + child: Widget.Label({ + hpack: "center", + label: icon, + class_name: "awesome_icon icon" + }), + }), + Widget.Label({ + label: label, + class_name: "label", + }) + ] + }), + on_clicked: () => { + shown.setValue(page) + } + }) +} + + +export function Navigation() { + const messages_apps = ["discord", "materialgram", "Telegram Desktop"] + let stack = Widget.Stack({ + children: { + "Messages": NotificationsBox({ include: messages_apps }), + "Notifications": NotificationsBox({ exclude: messages_apps }), + "System": SystemBox() + }, + transition: "crossfade", + transitionDuration: 200, + // @ts-ignore + shown: shown.bind() + }) + const buttons = Widget.Box({ + class_name: "navigation", + hexpand: true, + children: [ + Button({ + page: "Messages", + label: "Messages", + icon: "" + }), + Button({ + page: "Notifications", + label: "Notifs", + icon: "" + }), + Button({ + page: "System", + label: "System", + icon: "" + }) + ] + }) + return Widget.Box({ + vexpand: true, + orientation: Gtk.Orientation.VERTICAL, + class_name: "sidebar_bottom", + children: [ + stack, + buttons + ] + }) +} diff --git a/config/ags/modules/sidebar/notifications-old.ts b/config/ags/modules/sidebar/notifications-old.ts new file mode 100644 index 00000000..4d735943 --- /dev/null +++ b/config/ags/modules/sidebar/notifications-old.ts @@ -0,0 +1,183 @@ +import { Notification as NotificationType } from "types/service/notifications"; + +const notifications = await Service.import("notifications") +const { Gtk, Gdk } = imports.gi; + +function NotificationIcon({ app_entry, app_icon, image }: NotificationType) { + if (image) { + return Widget.Box({ + css: `background-image: url("${image}");` + + "background-size: contain;" + + "background-repeat: no-repeat;" + + "background-position: center;", + }) + } + + let icon = "dialog-information-symbolic" + if (Utils.lookUpIcon(app_icon)) + icon = app_icon + + if (app_entry && Utils.lookUpIcon(app_entry)) + icon = app_entry + + return Widget.Box({ + child: Widget.Icon(icon), + }) +} + + +function Notification(n: NotificationType) { + const icon = Widget.Box({ + vpack: "start", + class_name: "notification_sidebar_icon", + child: NotificationIcon(n), + }) + + const title = Widget.Label({ + class_name: "notification_sidebar_title", + wrap: true, + label: n.summary, + use_markup: true, + hpack: "start", + xalign: 0 + }) + + const body = Widget.Label({ + class_name: "notification_sidebar_body", + label: n.body, + wrap: true, + use_markup: true, + hpack: "start", + xalign: 0 + }) + + const actions = Widget.Box({ + halign: Gtk.Align.END, + class_name: "notification_sidebar_actions", + children: n.actions.map(({ id, label }) => Widget.Button({ + class_name: "notification_sidebar_button", + on_clicked: () => { + n.invoke(id) + }, + hexpand: false, + child: Widget.Label(label), + })), + }) + + let Box = Widget.EventBox( + { + attribute: { id: n.id }, + on_secondary_click: () => n.close(), + }, + Widget.Box( + { + class_name: `notification_sidebar ${n.urgency}`, + vertical: true, + }, + Widget.Box([ + icon, + Widget.Box( + { + vertical: true, + hexpand: true, + }, + title, + body, + ), + ]), + actions, + ), + ) + return Box +} + +type NotificationsBoxType = { + exclude?: string[], + include?: string[] +} + +export function NotificationsBox({ exclude = [], include = [] }: NotificationsBoxType) { + let isEmpty = Variable(false) + const list = Widget.Box({ + vertical: true, + children: notifications.popups.map(Notification) + }) + + const _list = Widget.Box({ + vertical: true, + children: [ + list, + Widget.Label({ + label: "Empty", + visible: isEmpty.bind(), + class_name: "empty" + }) + ], + class_name: "notifications_list_sidebar" + }) + + function setIsEmpty() { + if (list.children.length > 0) isEmpty.setValue(false) + else isEmpty.setValue(true) + } + + function onNotified(_: any, id: number) { + const n = notifications.getNotification(id) + if (n) { + if (exclude.includes(n.app_name.trim())) + return + if (include.length == 0 || include.includes(n.app_name.trim())) { + const notificationWidget = Notification(n) + list.children = [notificationWidget, ...list.children] + setIsEmpty() + } + } + } + + function onClosed(_: any, id: number) { + list.children.find(n => n.attribute.id === id)?.destroy() + setIsEmpty() + } + list.hook(notifications, onNotified, "notified") + .hook(notifications, onClosed, "closed") + + const menu = Widget.Menu({ + class_name: "notifications_menu", + children: [ + Widget.MenuItem({ + child: Widget.Label('Close all'), + class_name: "notifications_menu_item", + on_activate: () => { + for (let x of list.children) { + const n = notifications.getNotification(x.attribute.id) + if (n) { + n.dismiss() + n.close() + } + } + } + }), + ], + }) + + return Widget.EventBox({ + vexpand: true, + hexpand: true, + on_secondary_click: (_, event) => { + menu.popup_at_pointer(event) + }, + child: Widget.Scrollable({ + class_name: "notifications_sidebar_scrollable", + hscroll: "never", + child: _list, + hexpand: true + + /** this is a simple one liner that could be used instead of + hooking into the 'notified' and 'dismissed' signals. + but its not very optimized becuase it will recreate + the whole list everytime a notification is added or dismissed */ + // children: notifications.bind('popups') + // .as(popups => popups.map(Notification)) + }), + }) +} diff --git a/config/ags/modules/sidebar/notifications.ts b/config/ags/modules/sidebar/notifications.ts new file mode 100644 index 00000000..9b35ea1f --- /dev/null +++ b/config/ags/modules/sidebar/notifications.ts @@ -0,0 +1,76 @@ +import { Notification as NotificationType } from "types/service/notifications"; +import { NotificationPopups, Notification } from "modules/notificationPopups"; +import Box from "types/widgets/box"; + +const notifications = await Service.import("notifications") +const { Gtk, Gdk } = imports.gi; + +type NotificationsBoxType = { + exclude?: string[], + include?: string[] +} + +const NotificationNoReveal = (notification: NotificationType, visible = false, dismiss = true) => { + type BoxAttrs = { + destroyWithAnims: any, + count: number, + id: number, + } + + const _notification = Notification(notification, dismiss); + + let box: Box; + + const destroyWithAnims = () => { + box.destroy(); + }; + box = Widget.Box({ + hexpand: true, + attribute: { + "destroyWithAnims": destroyWithAnims, + count: 0, + id: notification.id, + }, + children: [_notification], + }); + return box; +}; + +export function NotificationsBox({ exclude = [], include = [] }: NotificationsBoxType) { + const popups = NotificationPopups( + false, { exclude: exclude, include: include }, + false, NotificationNoReveal + ); + + const menu = Widget.Menu({ + class_name: "notifications_menu", + children: [ + Widget.MenuItem({ + child: Widget.Label('Close all'), + class_name: "notifications_menu_item", + on_activate: () => { + for (let n of notifications.notifications) { + if (n) { + n.dismiss() + n.close() + } + } + } + }), + ], + }) + + return Widget.EventBox({ + vexpand: true, + hexpand: true, + on_secondary_click: (_, event) => { + menu.popup_at_pointer(event) + }, + child: Widget.Scrollable({ + class_name: "notifications_sidebar_scrollable", + hscroll: "never", + child: popups, + hexpand: true + }), + }) +} diff --git a/config/ags/modules/sidebar/sidebar.ts b/config/ags/modules/sidebar/sidebar.ts new file mode 100644 index 00000000..9956919a --- /dev/null +++ b/config/ags/modules/sidebar/sidebar.ts @@ -0,0 +1,18 @@ +import { Management } from "./management.ts" +import { Buttons } from "./buttons.ts"; +import { Navigation } from "./navigation.ts"; +const { Gtk } = imports.gi; + +export function SideBar() { + return Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "sidebar_main_box", + hexpand: true, + children: [ + Management(), + Buttons(), + Navigation() + // NotificationsBox() + ] + }) +} diff --git a/config/ags/modules/sidebar/system.ts b/config/ags/modules/sidebar/system.ts new file mode 100644 index 00000000..3164ac64 --- /dev/null +++ b/config/ags/modules/sidebar/system.ts @@ -0,0 +1,210 @@ +import { Variable as VariableType } from "types/variable"; + +const { Gtk } = imports.gi; + +const cpu_name = await Utils.execAsync(`${App.configDir}/scripts/system.sh --cpu-name`); +const cpu_cores = await Utils.execAsync(`${App.configDir}/scripts/system.sh --cpu-cores`); +const amount_of_ram = await Utils.execAsync(`${App.configDir}/scripts/system.sh --ram`); +const kernel_name = await Utils.execAsync(`${App.configDir}/scripts/system.sh --kernel`); + +type InfoType = { + cpu: string, + ram: string, + swap: string, + cpu_temp: string +} + +async function SystemInfo(): Promise { + const cpu_usage = await Utils.execAsync(`${App.configDir}/scripts/system.sh --cpu-usage`) + .then(str => String(str)) + .catch(err => { + print(err) + return "0" + }); + const ram_usage = await Utils.execAsync(`${App.configDir}/scripts/system.sh --ram-usage`) + .then(str => String(str)) + .catch(err => { + print(err) + return "0" + }); + const swap_usage = await Utils.execAsync(`${App.configDir}/scripts/system.sh --swap-usage`) + .then(str => String(str)) + .catch(err => { + print(err) + return "0" + }); + const cpu_temp = await Utils.execAsync(`${App.configDir}/scripts/system.sh --cpu-temp`) + .then(str => String(str)) + .catch(err => { + print(err) + return "0" + }); + return { + cpu: cpu_usage, + ram: ram_usage, + swap: swap_usage, + cpu_temp: cpu_temp + } +} + +const usage = Variable({ + cpu: "0", + ram: "0", + swap: "0", + cpu_temp: "0" +} as unknown as Promise, { + poll: [1000, async () => { + const result = await SystemInfo() + .then(result => result) + return result + }] +}) + +function checkBacklight() { + const get = Utils.execAsync(`${App.configDir}/scripts/backlight.sh --get`) + .then(out => Number(out.trim())) + .catch(print); + return get +} + +function checkBrightness() { + const get = Utils.execAsync(`${App.configDir}/scripts/brightness.sh --get`) + .then(out => Number(out.trim())) + .catch(print); + return get +} + +const current_backlight = Variable(100, { + poll: [500, checkBacklight] +}) + +const current_brightness = Variable(100, { + poll: [500, checkBrightness] +}) + +const Usage = ( + name: string, var_name: keyof InfoType, + class_name: string | undefined +) => { + const usage_progress_bar = Widget.ProgressBar({ + class_name: "usage_bar", + value: usage.bind().as(usage => Number(usage[var_name]) / 100), + }) + const usage_overlay = Widget.Overlay({ + child: usage_progress_bar, + overlay: Widget.Box({ + halign: Gtk.Align.END, + valign: Gtk.Align.CENTER, + class_name: "usage_bar_point" + }) + }) + const _usage = Widget.Box({ + class_name: `${class_name} usage_box`, + orientation: Gtk.Orientation.VERTICAL, + children: [ + Widget.Label({ + label: usage.bind().as(usage => `${name}: ${usage[var_name]}%`), + hpack: "start", + vpack: "center" + }), + usage_overlay + ] + }) + + return _usage +} + +const InfoLabel = (name: string, var_name: keyof InfoType, end: string) => { + return Widget.Label({ + class_name: "info_label", + truncate: "end", + hpack: "start", + label: usage.bind().as(usage => `${name}: ${usage[var_name]}${end}`) + }) +} + +const InfoLabelString = (name: string, value: string, end: string) => { + return Widget.Label({ + class_name: "info_label", + truncate: "end", + hpack: "start", + label: `${name}: ${value}${end}` + }) +} + +export function SystemBox() { + const backlight = Widget.Slider({ + min: 0, + max: 100, + draw_value: false, + class_name: "system_scale backlight", + // @ts-ignore + value: current_backlight.bind(), + on_change: self => { + current_backlight.setValue(Number(self.value)); + Utils.execAsync(`${App.configDir}/scripts/backlight.sh --smooth ${self.value}`) + .catch(print); + }, + tooltip_markup: "Backlight" + }) + const brightness = Widget.Slider({ + min: 0, + max: 1, + draw_value: false, + class_name: "system_scale brightness", + // @ts-ignore + value: current_brightness.bind(), + on_change: self => { + current_brightness.setValue(Number(self.value)); + Utils.execAsync(`${App.configDir}/scripts/brightness.sh --set ${self.value}`) + .catch(print); + }, + tooltip_markup: "Brightness" + }) + const slider_box = Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "slider_box", + children: [ + backlight, + brightness + ] + }) + + const usage_box = Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "usage_box", + spacing: 0, + children: [ + Usage("CPU", "cpu", "cpu_usage"), + Usage("RAM", "ram", "ram_usage"), + Usage("SWAP", "swap", "swap_usage") + ] + }) + + const info_box = Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "info_box", + spacing: 0, + children: [ + InfoLabel("CPU temp", "cpu_temp", "°C"), + InfoLabelString("CPU name", cpu_name, ""), + InfoLabelString("CPU cores", cpu_cores, ""), + InfoLabelString("RAM amount", amount_of_ram, ""), + InfoLabelString("Kernel", kernel_name, "") + ], + vexpand: true + }) + + return Widget.Scrollable({ + child: Widget.Box({ + orientation: Gtk.Orientation.VERTICAL, + class_name: "system_box", + spacing: 10, + children: [ + slider_box, + usage_box, + info_box + ] + }) + }) +} diff --git a/config/ags/scripts/backlight.sh b/config/ags/scripts/backlight.sh new file mode 100755 index 00000000..c9846b5e --- /dev/null +++ b/config/ags/scripts/backlight.sh @@ -0,0 +1,88 @@ +#!/bin/bash +LOCKFILE=/tmp/smooth_backlight.lock +BRIGHTNESS=/tmp/set_backlight +smooth() { + if [ -n "$1" ]; then + rounded_value=$(echo "scale=0; $1/1" | bc) + echo $rounded_value > $BRIGHTNESS + else + echo "Not enough arguments" + exit 1 + fi + + if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then + echo "locked" + exit 0 + fi + + trap "rm -f $LOCKFILE; exit" INT TERM EXIT + echo $$ > "$LOCKFILE" + + smooth_brightness() { + local max_brightness=$(brightnessctl m) + local step=$((max_brightness / 100)) + + while true; do + local target_brightness=$(cat $BRIGHTNESS) + local current_brightness=$(brightnessctl g) + target_brightness=$(echo "$max_brightness * $target_brightness / 100" | bc) + + if [ $current_brightness -eq $target_brightness ]; then + exit 0 + fi + while [ $current_brightness -ne $target_brightness ]; do + if [ $current_brightness -lt $target_brightness ]; then + current_brightness=$((current_brightness + step)) + else + current_brightness=$((current_brightness - step)) + fi + + brightnessctl s $current_brightness > /dev/null 2>&1 + sleep 0.001 + + local new_target_brightness=$(cat $BRIGHTNESS) + new_target_brightness=$(echo "$max_brightness * $new_target_brightness / 100" | bc) + if [ $new_target_brightness -ne $target_brightness ]; then + target_brightness=$new_target_brightness + break + fi + done + + done + } + + smooth_brightness + + rm -f "$LOCKFILE" + trap - INT TERM EXIT +} + +set() { + if [ -n "$1" ]; then + brightnessctl s $1 + else + echo "Not enough arguments" + exit 1 + fi +} + +get() { + if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then + local target_brightness=$(cat $BRIGHTNESS) + echo $target_brightness + exit 0 + fi + brightness=$(brightnessctl g) + max_brightness=$(brightnessctl m) + percentage=$((100 * brightness / max_brightness)) + + echo "$percentage" +} + +if [[ "$1" == "--smooth" ]]; then + smooth $2 + elif [[ "$1" == "--set" ]]; then + set $2 + elif [[ "$1" == "--get" ]]; then + get +fi diff --git a/config/ags/scripts/bluetooth.sh b/config/ags/scripts/bluetooth.sh new file mode 100755 index 00000000..33285ed9 --- /dev/null +++ b/config/ags/scripts/bluetooth.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +monitor() { + old_status=$(bluetoothctl show | grep "Powered: " | awk '{print $2}') + + while true; do + status=$(bluetoothctl show | grep "Powered: " | awk '{print $2}') + + if [ "$status" != "$old_status" ]; then + echo $status + old_status=$status + fi + + sleep 1 + done +} + +get_status() { + status=$(bluetoothctl show | grep "Powered: " | awk '{print $2}') + echo $status +} + +set() { + power=$1 + bluetoothctl power $power +} + +toggle() { + status=$(bluetoothctl show | grep "Powered: " | awk '{print $2}') + if [[ $status == "yes" ]]; then + bluetoothctl power off > /dev/null + get_status + else + bluetoothctl power on > /dev/null + get_status + fi +} + +if [[ "$1" == "--get" ]]; then + get_status + elif [[ "$1" == "--set" ]]; then + { set "$2"; } + elif [[ "$1" == "--monitor" ]]; then + monitor + elif [[ "$1" == "--toggle" ]]; then + toggle +fi diff --git a/config/ags/scripts/brightness.sh b/config/ags/scripts/brightness.sh new file mode 100755 index 00000000..37cf835e --- /dev/null +++ b/config/ags/scripts/brightness.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# I tried to make it smooth, but it didn't work + + +LOCKFILE=/tmp/brightness.lock + +get_brightness() { + busctl --user get-property rs.wl-gammarelay / rs.wl.gammarelay Brightness | awk '{print $2}' +} + +set_brightness() { + # if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then + # exit 0 + # fi + # trap "rm -f $LOCKFILE; exit" INT TERM EXIT + # echo $$ > "$LOCKFILE" + if (( $(echo "$1 < 0.05" | bc -l) )); then + BRIGHTNESS=0.05 + else + BRIGHTNESS=$1 + fi + busctl --user -- set-property rs.wl-gammarelay / rs.wl.gammarelay Brightness d $BRIGHTNESS + # rm -f "$LOCKFILE" + # trap - INT TERM EXIT +} + +set() { + if [ -n "$1" ]; then + set_brightness $1 + else + echo "Not enough arguments" + exit 1 + fi +} + +get() { + if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then + local target_brightness=$(cat $BRIGHTNESS) + echo $target_brightness + exit 0 + fi + percentage=$(get_brightness) + + echo "$percentage" +} + +if [[ "$1" == "--set" ]]; then + set $2 + elif [[ "$1" == "--get" ]]; then + get +fi diff --git a/config/ags/scripts/cliphist.sh b/config/ags/scripts/cliphist.sh new file mode 100755 index 00000000..d31b0012 --- /dev/null +++ b/config/ags/scripts/cliphist.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +get() { + clip_list=$(cliphist list) + + while IFS= read -r line; do + echo "$line" | iconv -t UTF-8 + done <<< "$clip_list" +} + +copy_by_id() { + id=$1 + cliphist decode $id | wl-copy +} + +if [[ "$1" == "--get" ]]; then + get +elif [[ "$1" == "--copy-by-id" ]]; then + { copy_by_id "$2"; } +fi + diff --git a/config/ags/scripts/network.sh b/config/ags/scripts/network.sh new file mode 100755 index 00000000..03b5592c --- /dev/null +++ b/config/ags/scripts/network.sh @@ -0,0 +1,29 @@ +#!/bin/bash +get_uuid() { + local SSID="$1" + local UUID=$(nmcli connection show | grep "$SSID" | grep wifi | awk '{print $2}') + if [ -z "$UUID" ]; then + echo undefined + exit 1 + else + echo $UUID + fi +} + +edit_by_ssid() { + local SSID="$1" + local UUID=$(get_uuid $SSID) + nm-connection-editor -e $UUID +} + +saved_networks() { + nmcli connection show | grep "$SSID" | grep wifi | awk '{print $1}' +} + +if [[ "$1" == "--get" ]]; then + get_uuid $2 +elif [[ "$1" == "--edit" ]]; then + edit_by_ssid $2 +elif [[ "$1" == "--saved" ]]; then + saved_networks +fi diff --git a/config/ags/scripts/night-light.sh b/config/ags/scripts/night-light.sh new file mode 100755 index 00000000..cae986fe --- /dev/null +++ b/config/ags/scripts/night-light.sh @@ -0,0 +1,134 @@ +#!/bin/bash + + +get_current_temperature() { + busctl --user get-property rs.wl-gammarelay / rs.wl.gammarelay Temperature | awk '{print $2}' +} + +set_temperature() { + busctl --user set-property rs.wl-gammarelay / rs.wl.gammarelay Temperature q $1 +} + +toggle() { + LOCKFILE=/tmp/smooth_toggle_night_light.lock + ENABLE=/tmp/enable + + if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then + if [ -e "$ENABLE" ]; then + if [[ $(cat $ENABLE) == "1" ]]; then + echo 0 > $ENABLE + echo "disabled" + else + echo 1 > $ENABLE + echo "enabled" + fi + fi + exit 0 + fi + + trap "rm -f $LOCKFILE; exit" INT TERM EXIT + echo $$ > "$LOCKFILE" + + current_temp=$(get_current_temperature) + + day_temp=6500 + night_temp=3500 + step=50 + delay=0.005 + + smooth_change() { + local start_temp=$1 + local end_temp=$2 + local increment + + if [ "$start_temp" -lt "$end_temp" ]; then + increment=$step + else + increment=-$step + fi + + temp=$start_temp + while [ "$temp" -ne "$end_temp" ]; do + local mode=$(cat $ENABLE) + + if [ "$mode" -eq 0 ]; then + end_temp=$day_temp + else + end_temp=$night_temp + fi + + if [ "$temp" -eq "$end_temp" ]; then + sleep 1 + continue + fi + + set_temperature $temp + + if [ "$increment" -gt 0 ] && [ "$temp" -gt "$end_temp" ]; then + temp=$end_temp + elif [ "$increment" -lt 0 ] && [ "$temp" -lt "$end_temp" ]; then + temp=$end_temp + else + temp=$((temp + increment)) + fi + + sleep $delay + + local new_mode=$(cat $ENABLE) + + if [ "$new_mode" -ne "$mode" ]; then + if [ "$new_mode" -eq 0 ]; then + end_temp=$day_temp + else + end_temp=$night_temp + fi + + if [ "$temp" -lt "$end_temp" ]; then + increment=$step + else + increment=-$step + fi + + temp=$(get_current_temperature) + fi + done + if [ -e "$ENABLE" ]; then + if [[ $(cat $ENABLE) == "1" ]]; then + echo "enabled" + else + echo "disabled" + fi + fi + set_temperature $end_temp + } + + if [ "$current_temp" -lt "$(( (day_temp + night_temp) / 2 ))" ]; then + echo 0 > $ENABLE + smooth_change $current_temp $day_temp + else + echo 1 > $ENABLE + smooth_change $current_temp $night_temp + fi + + rm -f "$LOCKFILE" + trap - INT TERM EXIT +} + +get() { + day_temp=6500 + night_temp=5000 + + current_temp=$(get_current_temperature) + + if [ "$current_temp" -lt "$(( (day_temp + night_temp) / 2 ))" ]; then + echo "enabled" + else + echo "disabled" + fi +} + +if [[ "$1" == "--toggle" ]]; then + toggle + elif [[ "$1" == "--get" ]]; then + get +fi diff --git a/config/ags/scripts/system.sh b/config/ags/scripts/system.sh new file mode 100755 index 00000000..3cb9552c --- /dev/null +++ b/config/ags/scripts/system.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +get_cpu_usage() { + top -bn1 | grep "Cpu(s)" | \ + awk '{printf "%.0f\n", $2 + $4 + $6}' +} + +get_ram_usage() { + free -m | awk 'NR==2{printf "%.0f\n", $3*100/$2 }' +} + +get_swap_usage() { + free -m | awk 'NR==3{printf "%.0f\n", $3*100/$2 }' +} + +get_cpu_temp() { + sensors | grep -i 'core ' | awk '{sum+=$3; count+=1} END {if (count > 0) print sum/count; else print "Undefined"}' +} + +get_cpu_name() { + lscpu | awk -F ': +' '/Model name/ {sub(" @ .*", "", $2); print $2}' +} + +get_ram() { + free -h | grep Mem | awk '{print $2}' +} + +get_kernel() { + uname -r +} + +if [[ "$1" == "--cpu-usage" ]]; then + get_cpu_usage + elif [[ "$1" == "--ram-usage" ]]; then + get_ram_usage + elif [[ "$1" == "--swap-usage" ]]; then + get_swap_usage + elif [[ "$1" == "--cpu-temp" ]]; then + get_cpu_temp + elif [[ "$1" == "--cpu-name" ]]; then + get_cpu_name + elif [[ "$1" == "--cpu-cores" ]]; then + nproc + elif [[ "$1" == "--ram" ]]; then + get_ram + elif [[ "$1" == "--kernel" ]]; then + get_kernel +fi diff --git a/config/ags/scripts/wayland-idle-inhibitor.py b/config/ags/scripts/wayland-idle-inhibitor.py new file mode 100755 index 00000000..c731f677 --- /dev/null +++ b/config/ags/scripts/wayland-idle-inhibitor.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +import sys +from dataclasses import dataclass +from signal import SIGINT, SIGTERM, signal +from threading import Event +import setproctitle + +from pywayland.client.display import Display # type: ignore +from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import ( # type: ignore + ZwpIdleInhibitManagerV1, +) +from pywayland.protocol.wayland.wl_compositor import WlCompositor # type: ignore +from pywayland.protocol.wayland.wl_registry import WlRegistryProxy # type: ignore +from pywayland.protocol.wayland.wl_surface import WlSurface # type: ignore + + +@dataclass +class GlobalRegistry: + surface: WlSurface | None = None + inhibit_manager: ZwpIdleInhibitManagerV1 | None = None + + +def handle_registry_global( + wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int +) -> None: + global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry() + + if iface_name == "wl_compositor": + compositor = wl_registry.bind(id_num, WlCompositor, version) + global_registry.surface = compositor.create_surface() # type: ignore + elif iface_name == "zwp_idle_inhibit_manager_v1": + global_registry.inhibit_manager = wl_registry.bind( + id_num, ZwpIdleInhibitManagerV1, version + ) + + +def main() -> None: + done = Event() + signal(SIGINT, lambda _, __: done.set()) + signal(SIGTERM, lambda _, __: done.set()) + + global_registry = GlobalRegistry() + + display = Display() + display.connect() + + registry = display.get_registry() # type: ignore + registry.user_data = global_registry + registry.dispatcher["global"] = handle_registry_global + + def shutdown() -> None: + display.dispatch() + display.roundtrip() + display.disconnect() + + display.dispatch() + display.roundtrip() + + if global_registry.surface is None or global_registry.inhibit_manager is None: + print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.") + shutdown() + sys.exit(1) + + inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore + global_registry.surface + ) + + display.dispatch() + display.roundtrip() + + print("Inhibiting idle...") + done.wait() + print("Shutting down...") + + inhibitor.destroy() + + shutdown() + + +if __name__ == "__main__": + setproctitle.setproctitle("wayland-idle-inhibitor.py") + main() diff --git a/config/ags/services/brightness.js b/config/ags/services/brightness.js deleted file mode 100644 index 861a7e30..00000000 --- a/config/ags/services/brightness.js +++ /dev/null @@ -1,71 +0,0 @@ -import { bash, sh } from "../functions/utils.js"; - -const get = (args) => Number(Utils.exec(`brightnessctl ${args}`)); -const screen = await bash`ls -w1 /sys/class/backlight | head -1`; -const kbd = await bash`ls -w1 /sys/class/leds | head -1`; - -class Brightness extends Service { - static { - Service.register( - this, - {}, - { - screen: ["float", "rw"], - kbd: ["int", "rw"], - }, - ); - } - - #kbdMax = get(`--device ${kbd} max`); - #kbd = get(`--device ${kbd} get`); - #screenMax = get("max"); - #screen = get("get") / get("max"); - - get kbd() { - return this.#kbd; - } - get screen() { - return this.#screen; - } - - set kbd(value) { - if (value < 0 || value > this.#kbdMax) return; - - sh(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { - this.#kbd = value; - this.changed("kbd"); - }); - } - - set screen(percent) { - if (percent < 0) percent = 0; - - if (percent > 1) percent = 1; - - sh(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { - this.#screen = percent; - this.changed("screen"); - }); - } - - constructor() { - super(); - - const screenPath = `/sys/class/backlight/${screen}/brightness`; - const kbdPath = `/sys/class/leds/${kbd}/brightness`; - - Utils.monitorFile(screenPath, async (f) => { - const v = await Utils.readFileAsync(f); - this.#screen = Number(v) / this.#screenMax; - this.changed("screen"); - }); - - Utils.monitorFile(kbdPath, async (f) => { - const v = await Utils.readFileAsync(f); - this.#kbd = Number(v) / this.#kbdMax; - this.changed("kbd"); - }); - } -} - -export default new Brightness(); diff --git a/config/ags/services/configuration.js b/config/ags/services/configuration.js deleted file mode 100644 index 7403c8f6..00000000 --- a/config/ags/services/configuration.js +++ /dev/null @@ -1,79 +0,0 @@ -// @ts-nocheck -import { Variable as Var } from "resource:///com/github/Aylur/ags/variable.js"; -import { deepMerge } from "../functions/utils.js"; -import { replacePlaceholders, reverseReplace } from "../functions/utils.js"; -export const configPath = App.configDir + "/config.json"; - -class Conf extends Var { - static { - Service.register(this); - } - - constructor(key, callback = () => null, replaceData = {}) { - super(""); - const config = JSON.parse(Utils.readFile(configPath) || "{}"); - this.key = key; - this.replaceData = replaceData; - this.setValue( - replacePlaceholders( - this.key.includes(".") - ? this.#accessNestedJson(config, this.key) - : config[this.key], - this.replaceData, - ), - ); - this.connect("changed", callback); - } - - key = ""; - replaceData = {}; - - #accessNestedJson(data, keys) { - const keysArray = keys.split("."); - let result = data; - for (const key of keysArray) { - if (key in result) { - result = result[key]; - } else { - return null; - } - } - return result; - } - - #createNestedJson(key, newvalue) { - const keysarray = key.split("."); - let result = {}; - let temp = result; - for (let i = 0; i < keysarray.length - 1; i++) { - temp[keysarray[i]] = {}; - temp = temp[keysarray[i]]; - } - temp[keysarray[keysarray.length - 1]] = newvalue; - return result; - } - - updateValue(value) { - super.setValue(value); - let json = {}; - if (!this.key.includes(".")) { - json[this.key] = value; - } else { - json = this.#createNestedJson( - this.key, - reverseReplace(value, this.replaceData), - ); - } - this.#setConfig(json); - } - - #setConfig(value) { - const configs = JSON.parse(Utils.readFile(configPath) || "{}"); - - const updatedConfig = deepMerge(configs, value); - const configString = JSON.stringify(updatedConfig, null, 2); // this.#betterStringify(updatedConfig); - Utils.writeFile(configString, configPath); - } -} - -export default (keyz, call, replace) => new Conf(keyz, call, replace); diff --git a/config/ags/services/network_speed.js b/config/ags/services/network_speed.js deleted file mode 100644 index 51d288fc..00000000 --- a/config/ags/services/network_speed.js +++ /dev/null @@ -1,108 +0,0 @@ -class NetworkSpeedService extends Service { - static { - Service.register( - this, - { - "upload-updated": ["float"], - "download-updated": ["float"], - }, - { - "upload-speed": ["float", "r"], - "download-speed": ["float", "r"], - interval: ["float", "rw"], - }, - ); - } - - #interval = 1000; - #lastTotalDownBytes = 0; - #lastTotalUpBytes = 0; - #downloadSpeed = 0; - #uploadSpeed = 0; - - get interval() { - return this.#interval; - } - - set interval(value) { - this.#interval = value; - } - - get download_speed() { - return this.#downloadSpeed; - } - - get upload_speed() { - return this.#uploadSpeed; - } - - constructor() { - super(); - - this.#onChange(); - } - - #onChange() { - Utils.interval(this.#interval, () => { - const content = Utils.exec("cat /proc/net/dev"); - const lines = content.split("\n"); - - // Caculate the sum of all interfaces' traffic line by line. - let totalDownBytes = 0; - let totalUpBytes = 0; - - for (let i = 0; i < lines.length; ++i) { - const fields = lines[i].trim().split(/\W+/); - if (fields.length <= 2) { - continue; - } - - // Skip virtual interfaces. - const interfce = fields[0]; - const currentInterfaceDownBytes = Number.parseInt(fields[1]); - const currentInterfaceUpBytes = Number.parseInt(fields[9]); - if ( - interfce === "lo" || - // Created by python-based bandwidth manager "traffictoll". - interfce.match(/^ifb[0-9]+/) || - // Created by lxd container manager. - interfce.match(/^lxdbr[0-9]+/) || - interfce.match(/^virbr[0-9]+/) || - interfce.match(/^br[0-9]+/) || - interfce.match(/^vnet[0-9]+/) || - interfce.match(/^tun[0-9]+/) || - interfce.match(/^tap[0-9]+/) || - isNaN(currentInterfaceDownBytes) || - isNaN(currentInterfaceUpBytes) - ) { - continue; - } - - totalDownBytes += currentInterfaceDownBytes; - totalUpBytes += currentInterfaceUpBytes; - } - - if (this.#lastTotalDownBytes === 0) { - this.#lastTotalDownBytes = totalDownBytes; - } - if (this.#lastTotalUpBytes === 0) { - this.#lastTotalUpBytes = totalUpBytes; - } - this.#downloadSpeed = - (totalDownBytes - this.#lastTotalDownBytes) / this.#interval; - this.#uploadSpeed = - (totalUpBytes - this.#lastTotalUpBytes) / this.#interval; - this.emit("changed"); - this.notify("download-speed"); - this.notify("upload-speed"); - this.emit("upload-updated", this.#uploadSpeed); - this.emit("download-updated", this.#downloadSpeed); - - this.#lastTotalDownBytes = totalDownBytes; - this.#lastTotalUpBytes = totalUpBytes; - }); - } -} -const service = new NetworkSpeedService(); - -export default service; diff --git a/config/ags/services/powermenu.js b/config/ags/services/powermenu.js deleted file mode 100644 index bca6b7f5..00000000 --- a/config/ags/services/powermenu.js +++ /dev/null @@ -1,54 +0,0 @@ -const options = { - lock: "hyprlock", - sleep: "systemctl suspend", - reboot: "systemctl reboot", - logout: "pkill -u user", - shutdown: "shutdown now", -}; - -class PowerMenu extends Service { - static { - Service.register( - this, - {}, - { - title: ["string"], - cmd: ["string"], - }, - ); - } - - #title = ""; - #cmd = ""; - - get title() { - return this.#title; - } - - get cmd() { - return this.#cmd; - } - - action(action) { - [this.#cmd, this.#title] = { - lock: [options.lock, "Lock"], - sleep: [options.sleep, "Sleep"], - reboot: [options.reboot, "Reboot"], - logout: [options.logout, "Log Out"], - shutdown: [options.shutdown, "Shutdown"], - }[action]; - - this.notify("cmd"); - this.notify("title"); - this.emit("changed"); - App.closeWindow("powermenu__window"); - App.openWindow("verification__window"); - } - - // readonly shutdown = () => { - // this.action("shutdown") - // } -} - -const powermenu = new PowerMenu(); -export default powermenu; diff --git a/config/ags/services/screen_record.js b/config/ags/services/screen_record.js deleted file mode 100644 index c44b5020..00000000 --- a/config/ags/services/screen_record.js +++ /dev/null @@ -1,94 +0,0 @@ -import GLib from "gi://GLib"; -import { sh, bash } from "../functions/utils.js"; - -const now = () => GLib.DateTime.new_now_local().format("%Y-%m-%d_%H-%M-%S"); - -class Recorder extends Service { - static { - Service.register( - this, - {}, - { - timer: ["int"], - recording: ["boolean"], - }, - ); - } - - #recordings = Utils.HOME + "/Videos/Screencasting"; - #screenshots = Utils.HOME + "/Pictures/Screenshots"; - #file = ""; - #interval = 0; - - recording = false; - timer = 0; - - async start() { - if (this.recording) return; - - Utils.ensureDirectory(this.#recordings); - this.#file = `${this.#recordings}/${now()}.mp4`; - sh( - `wf-recorder -g "${await sh("slurp")}" -f ${this.#file} --pixel-format yuv420p`, - ); - - this.recording = true; - this.changed("recording"); - - this.timer = 0; - this.#interval = Utils.interval(1000, () => { - this.changed("timer"); - this.timer++; - }); - } - - async stop() { - if (!this.recording) return; - - await bash("killall -INT wf-recorder"); - this.recording = false; - this.changed("recording"); - GLib.source_remove(this.#interval); - - Utils.notify({ - iconName: "video-x-generic-symbolic", - summary: "Screenrecord", - body: this.#file, - actions: { - "Show in Files": () => sh(`xdg-open ${this.#recordings}`), - View: () => sh(`xdg-open ${this.#file}`), - }, - }); - } - - async screenshot(full = false) { - const file = `${this.#screenshots}/${now()}.png`; - Utils.ensureDirectory(this.#screenshots); - - if (full) { - await sh(`grim ${file}`); - } else { - const size = await sh("slurp -b#00000066 -w 0"); - if (!size) return; - - await sh(`grim -g "${size}" ${file}`); - } - - bash(`wl-copy < ${file}`); - - Utils.notify({ - image: file, - summary: "Screenshot", - body: file, - actions: { - "Show in Files": () => sh(`xdg-open ${this.#screenshots}`), - View: () => sh(`xdg-open ${file}`), - Edit: () => sh(`swappy -f ${file}`), - }, - timeout: 5000, - }); - } -} -const service = new Recorder(); - -export default service; diff --git a/config/ags/style-apps.css b/config/ags/style-apps.css new file mode 100644 index 00000000..37890b53 --- /dev/null +++ b/config/ags/style-apps.css @@ -0,0 +1,157 @@ +@import "./colors.css"; + +/* ----------------------------------------------------- + * Settings + * ----------------------------------------------------- */ + +.settings .settings_title { + color: @onSurface; + background-color: @surfaceContainerLow; + font-weight: normal; + font-size: 22px; + padding-top: 6px; + padding-bottom: 6px; +} + +.settings .full_sidebar { + border-right: 1px solid; + border-color: @outlineVariant; +} + +.settings .page_title { + background-color: @surface; + font-weight: normal; + padding-left: 16px; + padding-top: 6px; + padding-bottom: 6px; + font-size: 20px; + border-bottom: 1px solid; + border-color: @outlineVariant; + /* margin-bottom: 3px; */ +} + +.settings .page_title { + color: @onSurfaceVariant; +} + +.settings .sidebar { + padding-left: 12px; + padding-right: 12px; + padding-top: 5px; + padding-bottom: 5px; + min-width: 250px; + background-color: @surfaceContainerLow; +} + +.settings .sidebar .row { + border-radius: 100px; + padding: 0px; + padding-right: 24px; + padding-left: 16px; + min-height: 56px; + background-color: @surfaceContainerLow; +} + +.settings .sidebar .row:hover { + background-color: mix(@onSurface, @surface, 0.92); +} + +.settings .sidebar .row.active { + background-color: @secondaryContainer; +} + +.settings .sidebar .row label { + color: @onSurfaceVariant; + font-weight: normal; + font-size: 16px; +} + +.settings .sidebar .row.active label { + color: @onSecondaryContainer; +} + +.settings .sidebar .row image { + margin-right: 12px; + color: @onSurfaceVariant; +} + +.settings .sidebar .row.active image { + margin-right: 12px; + color: @onSecondaryContainer; +} + +.settings .sidebar separator { + margin-right: 16px; + margin-left: 16px; + color: @outline; +} + +.settings .error_container { + padding-left: 16px; + padding-right: 16px; + background-color: @errorContainer; +} + +.settings .error_container label { + color: @onErrorContainer; +} + +/* Wifi */ + +.settings .wifi_toggle { + padding-left: 16px; + padding-right: 16px; + padding-top: 12px; + padding-bottom: 8px; +} + +.settings .wifi_toggle .title { + font-weight: normal; + font-size: 17px; + color: @onSurface +} + +.settings .wifi_toggle .description { + font-weight: normal; + font-size: 14px; + color: @onSurfaceVariant +} + +.settings .wifi_list .wifi_network { + padding-left: 16px; + padding-right: 16px; + padding-top: 8px; + padding-bottom: 8px; + border-radius: 0px; +} + +.settings .wifi_list .wifi_network:hover { + background-color: mix(@onSurface, @surface, 0.92) +} + +.settings .wifi_list .wifi_network .title { + font-weight: normal; + font-size: 16px; + color: @onSurface +} + +.settings .wifi_list .wifi_network .description { + font-weight: normal; + font-size: 14px; + color: @onSurfaceVariant +} + +.settings .wifi_list .wifi_network image { + color: @onSurfaceVariant; + margin-right: 16px; +} + +.settings .wifi_list .wifi_network.active image { + color: @primary; +} + +.settings box { + margin: 0px; + padding: 0px; +} + diff --git a/config/ags/style.css b/config/ags/style.css new file mode 100644 index 00000000..694d3b0f --- /dev/null +++ b/config/ags/style.css @@ -0,0 +1,942 @@ +@import "./colors.css"; + +window.bar { + background-color: @surface; + padding: 6px; +} + +.bar label { + font-weight: bold; +} + +button { + background: transparent; +} + +trough { +} + +/* slider { + background-color: @primary; + background-image: -gtk-scaled(url("sun-alt-svgrepo-com.png")); + background-size: 100px 100px; + color: @primary; + min-height: 10px; + min-width: 10px; + border-radius: 100px; +} */ + + +highlight { + border-radius: 100px; +} + +* { + border: none; + outline: none; + transition: 0.2s ease-in-out; + transition-property: border-color, background-color, color; + font-family: "Product Sans", Roboto, "Font Awesome 6 Free", Roboto, Helvetica, Arial, sans-serif; +} + +.corner { + background-color: @background; + border-radius: 2px; +} + +tooltip { + background-color: @surfaceContainer; + border-radius: 11px; + outline: none; + border: none; + box-shadow: none; +} + +tooltip label { + color: @onSurface; + outline: none; + border: none; + box-shadow: none; + font-weight: normal; +} + +menu separator { + color: @outline; +} + +separator { + color: @outline; + margin-right: 0px; + margin-left: 0px; + margin-top: 8px; + margin-bottom: 8px; + padding: 0px; +} + +/* ----------------------------------------------------- + * Modules + * ----------------------------------------------------- */ + +.modules-left, +.modules-center, +.modules-right { + /* background-color: @surface; */ + /* border-radius: 25px 25px 25px 25px; */ + padding: 6px; + /* border: solid 2px; */ + /* color: @outlineVariant; */ +} + +/* ----------------------------------------------------- + * Workspaces + * ----------------------------------------------------- */ + +.workspaces { + border-radius: 16px; + font-weight: bold; + font-style: normal; + font-size: 16px; + color: @onSurface; + background: @surfaceContainer; +} + +.workspaces * { + transition: all 0.35s ease-in-out; + transition-property: background-color, color, min-width; +} + +.workspaces button { + padding: 0px 5px; + margin: 4px 3px; + border-radius: 16px; + border: 0px; + color: @onSurface; +} + +.workspaces button.active { + color: @onSecondaryContainer; + background: @secondaryContainer; + border-radius: 16px; + min-width: 40px; +} + +.workspaces button:hover { + color: @onSurface; + background: @surfaceContainerHighest; + border-radius: 16px; +} + +.workspaces button.active:hover { + color: @onPrimaryContainer; + background: @primaryContainer; + border-radius: 16px; +} + +/* ----------------------------------------------------- + * Clock + * ----------------------------------------------------- */ + +.clock { + background-color: @surfaceContainer; + border-radius: 16px; + padding: 2px 10px 0px 10px; +} + +.time { + color: @onSurface; + font-size: 14px; +} + +.date { + color: @onSurface; + font-size: 10px; +} + +/* ----------------------------------------------------- + * Tray + * ----------------------------------------------------- */ + + +.tray { + background-color: @surfaceContainer; + border-radius: 16px; + padding: 2px 10px 0px 10px; +} + +.tray button { + margin: 0px; + padding: 0px; +} + +.tray image { + color: @onSurface; +} + +/* ----------------------------------------------------- + * Notifications + * ----------------------------------------------------- */ + +window.notification-popups box.notifications { + padding: 14px; +} + + +.notification-icon { + min-width: 68px; + min-height: 68px; + margin-right: 1em; +} + +.notification-icon image { + font-size: 58px; + /* to center the icon */ + margin: 5px; + color: @onSurface; +} + +.notification-icon box { + min-width: 68px; + min-height: 68px; + border-radius: 7px; +} + +.notification { + min-width: 350px; + border-radius: 24px; + padding: 1em; + margin: 1px; + background-color: @surfaceContainerLowest; +} + +.notification.critical { + border: 2px solid @error; +} + +.notification-title { + color: @foreground; + font-size: 1.4em; +} + +.notification-body { + color: @foreground; +} + +.notification-actions .notification-action-button { + margin: 0 .4em; + margin-top: .8em; +} + +.notification-action-button { + background-color: @primary; + color: @onPrimary; +} + +.notification-actions .notification-action-button:first-child { + margin-left: 0; +} + +.notification-actions .notification-action-button:last-child { + margin-right: 0; +} + +.notification-time { + color: @primary; +} + +/* ----------------------------------------------------- + * Applications + * ----------------------------------------------------- */ + +.applauncher_box { + border-radius: 24px; + background-color: @background; + border: 2px solid; + border-color: @outlineVariant; +} + +.applauncher_box { + padding: 11px; +} + +.applauncher_entry { + background-color: @surfaceContainerHigh; + border: none; + outline: none; + border-radius: 100px; + margin-bottom: 16px; + padding: 5px; + font-weight: normal; + padding-left: 25px; +} + +.application_container label { + color: @onSurface; + font-weight: normal; +} + +.application_container { + border-radius: 100px; + border: none; + outline: none; +} + +.application_container:hover { + background-color: @surfaceContainerHighest; +} + +.application_container:focus label { + color: @onPrimary; +} + +.application_container:focus { + background-color: @primary; + border: 0px solid; + border-radius: 34px; + border: none; + outline: none; +} + +.application_divider { + color: @outline; + margin: 5px 0px 5px 0px; +} + +.application_label { + color: @onSurface +} + +.application_icon { + margin-right: 16px; + color: @onSurface; +} + +/* ----------------------------------------------------- + * Clipboard history + * ----------------------------------------------------- */ + + .cliphistory_box { + border-radius: 24px; + background-color: @background; + border: 2px solid; + border-color: @outlineVariant; +} + +.cliphistory_box { + padding: 11px; +} + +.cliphistory_entry { + background-color: @surfaceContainerHigh; + color: @onSurface; + border: none; + outline: none; + border-radius: 100px; + margin-bottom: 16px; + padding: 5px; + padding-left: 25px; +} + +.entry_container { + border-radius: 100px; + border: none; + outline: none; + min-height: 30px; +} + +.entry_container:hover { + background-color: @surfaceContainerHighest; +} + +.entry_container:focus .entry_label { + color: @onPrimary; +} + +.entry_container:focus { + background-color: @primary; + border: 0px solid; + border-radius: 34px; + border: none; + outline: none; +} + +.entry_divider { + color: @outline; + margin: 5px 0px 5px 0px; +} + +.entry_label { + color: @onSurface; + font-weight: normal; +} + +/* ----------------------------------------------------- + * Media player + * ----------------------------------------------------- */ + +.player { + background-color: @background; + padding: 15px; + min-width: 350px; + border: 2px solid @outlineVariant; + border-radius: 24px; +} + +.player .img { + min-width: 100px; + min-height: 100px; + background-size: cover; + background-position: center; + border-radius: 13px; + color: @foreground; +} + +.player .title { + font-size: 1.2em; + margin-left: 10px; + color: @foreground; +} + +.player .artist { + font-size: 1.1em; + margin-left: 10px; + color: @foreground; +} + +.player .length { + color: @foreground; +} + +.player .position { + color: @foreground; + margin-left: 10px; +} + +.player .icon { + color: @foreground +} + +.player scale.position { + padding: 0; + margin-bottom: .3em; + margin-left: 10px; +} + +.player scale.position trough { + background-color: @secondaryContainer; + min-height: 8px; +} + +.player scale.position highlight { + background-color: @primary; +} + +.player scale.position slider { + all: unset; +} + +.player button { + min-height: 1em; + min-width: 1em; + padding: .3em; + color: @onSecondary; +} + +.player button image { + color: @onSecondary; +} + +.player_buttons { + background-color: @secondary; + border-radius: 100px; + padding: 3px; + margin-top: 2px; +} + +/* ----------------------------------------------------- + * Misc + * ----------------------------------------------------- */ + +.bold_label { + font-weight: bold; +} + +.keyboard { + background-color: @surfaceContainer; + color: @onSurface; + padding: 0px 10px 0px 10px; + border-radius: 100px; +} + +.volume_box image { + margin-right: 5px; +} + +.awesome_icon { + font-family: "Font Awesome 6 Free"; +} + +.battery { + background-color: @surfaceContainer; + border-radius: 100px; + padding: 2px 10px 2px 10px; +} + +.battery label { + color: @onSurface; +} + +.battery image { + color: @onSurface; +} + +.bar_wifi { + background-color: @surfaceContainer; + border-radius: 100px; + padding: 2px 10px 2px 10px; +} + +.bar_wifi image { + color: @onSurface; +} + +/* ----------------------------------------------------- + * Sidebar + * ----------------------------------------------------- */ + +.sidebar_main_box { + background: @surfaceContainerLowest; +} + +.sidebar_main_box .empty { + color: @onSurface; +} + +.management_box { + padding: 15px; + padding-bottom: 0px; + outline: none; + border: none; +} + +.management_button { + min-width: 170px; + min-height: 50px; +} + +.management_button { + border-radius: 25px; + background: @surfaceContainer; + border: none; + outline: none; +} + +.management_button label { + color: @onSurface; + font-weight: normal; +} + +.ssid { + font-size: 12px; +} + +.management_button .icon { + color: @onSurface +} + +.management_button:hover { + background-color: @surfaceContainerHigh; +} + +.management_button.active label { + color: @onPrimary +} + +.management_button.active .icon { + color: @onPrimary +} + +.management_button.active { + background-color: @primary; + border: 0px solid; +} + +.management_button.waiting label { + color: @onError +} + +.management_button.waiting .icon { + color: @onError +} + +.management_button.waiting { + background-color: @error; + border: 0px solid; +} + +.management_button.disabled { + background: transparent; +} + +.sidebar_bottom { + background-color: @surfaceContainerLow; + border-radius: 24px 24px 0px 0px; + transition: all 0.25s ease-in-out; + /* border-radius: 0px 0px 24px 24px; */ +} + +.notifications_sidebar_scrollable .notification { + margin-left: 10px; + margin-right: 9px; + border-radius: 14px; + margin-top: 10px; + padding: 15px; + background-color: @background; + transition: all 0.25s ease-in-out; +} + +.notifications_sidebar_scrollable .notification-time { + color: @primary; +} + +.notifications_sidebar_scrollable { + padding-right: 1px; + color: @primary; +} + +.system_box { + padding: 10px; +} + +.system_scale slider { + color: @onPrimary; + background-color: @primary; + background-size: 20px 20px; + min-width: 30px; + min-height: 23px; + border-radius: 100px; + padding: 0px; + background-repeat: no-repeat; + background-position: center; + margin-left: 0px; + margin-right: 0px; + margin-top: -16px; + margin-bottom: -16px; + +} + +.system_scale.backlight slider { + background-image: -gtk-scaled(url("svg/brightness-onPrimary.svg")); +} + +.system_scale.backlight { + margin-bottom: 25px; +} + +.system_scale.brightness slider { + background-image: -gtk-scaled(url("svg/dark-onPrimary.svg")); +} + +.system_scale { + padding: 0px; + margin: 0px; +} + +.system_scale trough { + background-color: @secondaryContainer; + min-height: 6px; + margin-right: 4px; + margin-left: 4px; +} + +.system_scale highlight { + border-radius: 100px 0px 0px 100px; + + margin-top: -13px; + margin-bottom: -13px; + margin-left: -16px; + background-color: @primary; +} + +.system_box .slider_box, .system_box .usage_box, .system_box .info_box { + background-color: @surfaceContainerLowest; + padding: 26px; + border-radius: 14px; +} + +.system_box .usage_box { + padding: 10px; +} + +.system_box .info_box { + padding: 20px; +} + +.usage_bar trough { + background-color: @secondaryContainer; + min-height: 6px; +} + +.usage_bar progress { + min-width: 6px; + min-height: 6px; + background-color: @primary; + box-shadow: 5px 0px 0px 1px @surfaceContainerLowest; + border-radius: 100px; +} + +.usage_box label { + color: @onSurface +} + +.info_box label { + color: @onSurface +} + +.usage_bar_point { + background-color: @primary; + min-width: 6px; + min-height: 6px; + border-radius: 100%; +} + +.sidebar_buttons { + padding-left: 15px; + padding-right: 15px; + padding-bottom: 15px; + outline: none; + border: none; +} + +.dotbuttons_box { + margin-bottom: 15px; +} + +.dotbutton { + font-size: 10px; + margin: 0px; + padding: 3px; + transition: none; +} + +.dotbutton label { + color: @surfaceContainerHigh; +} + +.dotbutton:hover { +} + +.dotbutton.active label { + color: @secondary; +} + +/* +.notifications_menu { + padding: 0px; + min-width: 50px; +} + +.notifications_menu_item { + padding-right: 35px; + margin: 0px; +} */ + +/* ----------------------------------------------------- + * Buttons + * ----------------------------------------------------- */ + +/* outline */ +.outline_button { + background-color: transparent; + border: 1.2px solid; + border-color: @outline; + border-radius: 100px; + padding-left: 24px; + padding-right: 24px; +} + +.outline_button label, .outline_button .icon, +.outline_button .awesome_icon, .outline_button image { + color: @primary; +} + +.outline_button:hover { + background-color: mix(@primaryFixed, transparent, 0.8); +} + +.outline_button:focus { + background-color: mix(@primaryFixed, transparent, 0.8); + border-color: @primary; +} + +/* filled tonal */ +.filled_tonal_button { + background-color: @secondaryContainer; + color: @onSecondaryContainer; + border-radius: 100px; +} + +.filled_tonal_button label, .filled_tonal_button .icon, +.filled_tonal_button .awesome_icon, .filled_tonal_button image { + color: @onSecondaryContainer; +} + +.filled_tonal_button:hover { + background-color: mix(@secondaryContainer, @onSecondaryContainer, 0.05); + box-shadow: 00px 3px 3px -2px rgba(0, 0, 0, 0.2); +} + +.filled_tonal_button:active { + background-color: mix(@secondaryContainer, @onSecondaryContainer, 0.1); + box-shadow: none; +} +/* standard icon button */ +.standard_icon_button { + border-radius: 100px; + background-color: transparent; + color: @onSurfaceVariant; +} + +.standard_icon_button label, .standard_icon_button .icon, +.standard_icon_button .awesome_icon, .standard_icon_button image { + color: @onSurfaceVariant; + margin: 0px; + padding: 0px; +} + +.standard_icon_button:hover { + background-color: mix(@onSurfaceVariant, transparent, 0.8); +} + +.standard_icon_button:active { + background-color: mix(@onSurfaceVariant, transparent, 0.7); +} + + +/* ----------------------------------------------------- + * Navigation bar + * ----------------------------------------------------- */ + + + .navigation { + background-color: @surfaceContainer; + padding-top: 3px; + padding-bottom: 3px; +} + +.navigation .label { + font-weight: normal; + font-size: 12px; + margin-top: 3px; + color: @onSurface; +} + +.navigation_button .container { + border-radius: 16px; + padding: 5px; + min-height: 15px; + min-width: 0px; + transition-property: min-width, color, background-color, border-color; +} + +.navigation_button .icon { + font-weight: normal; + color: @onSurface; +} + +.navigation_button.active .icon { + font-weight: bold; + color: @onSecondaryContainer; +} + +.navigation_button .container_outer { + min-width: 60px; +} + +.navigation_button:hover .container { + background-color: mix(@onSurface, @surfaceContainer, 0.92); + min-width: 40px; +} + +.navigation_button:active .container { + background-color: mix(@onSurface, @surfaceContainer, 0.9); + min-width: 40px; +} + +.navigation_button.active .container { + background: @secondaryContainer; + min-width: 40px; +} + + +/* ----------------------------------------------------- + * Switch + * ----------------------------------------------------- */ + + +switch { + border: 2px solid; + border-radius: 100px; + border-color: @outline; + background-color: @surfaceContainerHighest; + min-height: 20px; + padding: 1px; +} + +switch slider { + border-radius: 100%; + background-color: @outline; + min-height: 10px; + margin: 2px; + min-height: 8px; + min-width: 16px; + transition: all 0.2s ease-in-out; + transition-property: min-height, min-width, color, background-color, border-color, margin; +} + +switch:disabled { + background-color: mix(@surfaceContainerHighest, transparent, 0.3); + border-color: mix(@onSurface, transparent, 0.3); +} + +switch:disabled slider { + background-color: mix(@onSurface, transparent, 0.3); +} + +switch:hover, switch:active { + background-color: mix(@surfaceContainerHighest, @onSurface, 0.08); +} + +switch:hover slider, switch:active slider { + background-color: @onSurfaceVariant; +} + +switch:checked { + background-color: @primary; + border-color: transparent; +} + +switch:checked slider { + background-color: @onPrimary; + border-color: transparent; + margin: 0px; + min-height: 10px; + min-width: 20px; +} + +switch:checked:disabled { + background-color: mix(@onSurface, transparent, 0.3); + border-color: transparent; +} + +switch:checked:disabled slider { + background-color: mix(@surface, transparent, 0.3); +} + +switch:checked:hover, switch:checked:active { + background-color: @primary; +} + +switch:checked:hover slider, switch:checked:active slider { + background-color: @primaryContainer; +} + diff --git a/config/ags/style/colors.scss b/config/ags/style/colors.scss deleted file mode 100644 index 9e49879d..00000000 --- a/config/ags/style/colors.scss +++ /dev/null @@ -1,48 +0,0 @@ -$background: #0f1416; -$error: #ffb4ab; -$error_container: #93000a; -$inverse_on_surface: #2c3134; -$inverse_primary: #05677e; -$inverse_surface: #dee3e6; -$on_background: #dee3e6; -$on_error: #690005; -$on_error_container: #ffdad6; -$on_primary: #003543; -$on_primary_container: #b6ebff; -$on_primary_fixed: #001f28; -$on_primary_fixed_variant: #004e60; -$on_secondary: #1e333b; -$on_secondary_container: #cfe6f0; -$on_secondary_fixed: #071e26; -$on_secondary_fixed_variant: #344a52; -$on_surface: #dee3e6; -$on_surface_variant: #bfc8cc; -$on_tertiary: #2c2e4d; -$on_tertiary_container: #e0e0ff; -$on_tertiary_fixed: #161937; -$on_tertiary_fixed_variant: #424465; -$outline: #8a9296; -$outline_variant: #40484c; -$primary: #87d1eb; -$primary_container: #004e60; -$primary_fixed: #b6ebff; -$primary_fixed_dim: #87d1eb; -$scrim: #000000; -$secondary: #b3cad4; -$secondary_container: #b3cad4; -$secondary_fixed: #cfe6f0; -$secondary_fixed_dim: #b3cad4; -$shadow: #000000; -$surface: #0f1416; -$surface_bright: #353a3c; -$surface_container: #1b2023; -$surface_container_high: #252b2d; -$surface_container_highest: #303638; -$surface_container_low: #171c1f; -$surface_container_lowest: #0a0f11; -$surface_dim: #0f1416; -$surface_variant: #40484c; -$tertiary: #c2c3eb; -$tertiary_container: #424465; -$tertiary_fixed: #e0e0ff; -$tertiary_fixed_dim: #c2c3eb; diff --git a/config/ags/style/common.scss b/config/ags/style/common.scss deleted file mode 100644 index 47caabad..00000000 --- a/config/ags/style/common.scss +++ /dev/null @@ -1,338 +0,0 @@ -* { - all: unset; - font-size: 14px; - font-family: "Ubuntu Nerd Font"; -} - -.window-content { - margin: $window_margin; - box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); - border-radius: $border-radius; - background-color: $background_color; - color: $on_background; - border: if($window_border, - 1px solid transparentize($on_background, 0.7), - none); -} - -.entry-box { - border-radius: $border_radius; - padding: 0px 8px; - min-height: 35px; - background-color: $primary; - color: $background; - font-weight: 600; - - image { - color: $background; - font-size: 16px; - } - - entry { - padding-left: 10px; - } -} - -scrolledwindow { - .item { - background-color: $on_secondary; - padding: 4px; - color: $on_background; - margin-left: 10px; - margin-right: 10px; - - image { - padding-right: 6px; - } - - &:last-child { - margin-bottom: 10px; - } - - .checkmark { - color: $primary; - } - - &:hover { - background-color: $primary_container; - } - - &:active { - background-color: transparent; - } - - &:focus { - background-color: $primary; - color: $background; - - label { - color: $background; - } - } - } -} - -button { - font-weight: 600; - border-radius: $border_radius; - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.4); - - &:hover { - background-color: $primary_container; - } -} - -.panel-button { - .panel-control-center { - &.empty { - color: transparentize($color: $on_background, $amount: 0.6); - } - } - - .panel-battery.charging { - color: $primary; - } - - &.active { - .panel-battery { - color: $background; - } - - .panel-control-center.empty { - color: $background; - } - } - - .timer.vert { - font-size: 12px; - } - - background-color: transparentize(if($dark_mode, $background, $on_secondary), - 1-$bar_button_opacity ); - color: $on_background; - padding: $panel_button_padding; - font-weight: 600; - // border-radius: divide-each($bar_border_radius, 1.5); - border-radius: $bar_button_border_radius; - // margin: $bar_padding; - // margin-top: nth($list: $bar_padding, $n: 1); - // margin-bottom: nth($list: $bar_padding, $n: 3); - box-shadow: if($bar_button_shadow, 1px 1px 2px rgba(0, 0, 0, 0.4), none); - - &:hover { - background-color: $primary_container; - } - - &.active { - background-color: $primary; - color: $background; - } -} - -.toggle-button { - background-color: $on_secondary; - color: $on_background; - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.4); - border-radius: divide-each($border_radius, 1.5); - - &:hover { - background-color: $primary_container; - } - - .icon { - margin-right: 8px; - } - - button { - box-shadow: unset; - border-radius: divide-each($border_radius, 1.5); - padding: 10px; - - &:first-child { - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - } - - &:last-child { - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - } - - &:hover { - background-color: $primary_container; - } - } - - &.active { - background-color: $primary; - color: $background; - - button:hover { - background-color: transparent; - } - } -} - -.menu { - background-color: $on_secondary; - margin: 0px 10px; - min-width: 280px; - border-radius: $border_radius; - border-top-left-radius: 0px; - border-top-right-radius: 0px; - - .title-box { - margin: 10px; - margin-bottom: 8px; - - .icon { - margin-right: 6px; - } - - .title { - font-size: 15px; - font-weight: 600; - } - } - - .content.vertical { - margin: 8px 0px; - - >*:first-child>* { - image { - margin-right: 6px; - } - - &:first-child { - margin-top: 0px; - } - - &:last-child { - margin-bottom: 0px; - } - - margin: 3px 10px; - border: 1px solid transparentize($color: $on_background, $amount: 0.8); - box-shadow: unset; - padding: 6px; - border-radius: divide-each($border_radius, 2); - } - } -} - -separator { - min-height: 1px; - background-color: transparentize($color: $on_background, $amount: 0.8); -} - -scale { - border-radius: $border_radius; - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.4); - - trough { - background-color: transparentize($color: $on_secondary, $amount: 0.3); - - border-radius: $border_radius; - min-height: 20px; - - highlight { - background-color: $primary; - border-radius: $border_radius; - } - } -} - -scrollbar { - background-color: $on_secondary; - border-radius: divide-each($border_radius, 2); - - slider { - min-width: 6px; - border-radius: divide-each($border_radius, 2); - background-color: $primary; - } -} - -levelbar { - trough { - box-shadow: 1px 1px 2px transparentize($color: rgb(0, 0, 0), $amount: 0.7); - border-radius: $border_radius; - - block { - &:first-child { - border-radius: $border_radius; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - } - - &:last-child { - border-radius: $border_radius; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - } - - &.empty { - background-color: $on_secondary; - } - - &.filled { - background-color: $primary; - } - } - } -} - -menuitem { - background-color: $on_secondary; - border-radius: divide-each($border_radius, 1.6); - margin: 4px 6px; - padding: 4px 15px; - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3); - - &:hover { - background-color: $primary_container; - } - - &:first-child { - margin-top: 6px; - } - - &:last-child { - margin-bottom: 6px; - } - - label { - font-size: 13px; - font-weight: 500; - } -} - -menu { - background-color: $background; - border-radius: divide-each($border_radius, 1.5); - color: $on_background; -} - -.splash-text { - font-size: 14px; - color: $on_background; - font-weight: 600; -} - -tooltip { - background-color: $background; - color: $on_background; - border-radius: divide-each($border_radius, 2); -} - -switch { - background-color: transparentize($color: $on_background, $amount: 0.8); - border-radius: $border_radius; - color: transparent; - - slider { - background-color: $primary; - border-radius: $border_radius; - min-width: 12px; - } -} diff --git a/config/ags/style/functions.scss b/config/ags/style/functions.scss deleted file mode 100644 index 4c71c140..00000000 --- a/config/ags/style/functions.scss +++ /dev/null @@ -1,13 +0,0 @@ -@function divide-each($value, $divider) { - $new-value: ( - ); - -@each $e in $value { - $new-value: append($new-value, $e / $divider); -} - -@return $new-value; -} - -//transparentize -$background_color: transparentize($background, 1-$window_opacity); diff --git a/config/ags/style/main.scss b/config/ags/style/main.scss deleted file mode 100644 index 3f02b9ce..00000000 --- a/config/ags/style/main.scss +++ /dev/null @@ -1,20 +0,0 @@ -@import "./colors.scss"; -@import "./vars.scss"; -@import "./functions.scss"; -@import "./common.scss"; -@import "./widgets/applauncher.scss"; -@import "./widgets/audio-popup.scss"; -@import "./widgets/bar.scss"; -@import "./widgets/battery-popup.scss"; -@import "./widgets/control-center.scss"; -@import "./widgets/datemenu.scss"; -@import "./widgets/media.scss"; -@import "./widgets/systray.scss"; -@import "./widgets/network-popup.scss"; -@import "./widgets/network-speed.scss"; -@import "./widgets/notifications.scss"; -@import "./widgets/osd.scss"; -@import "./widgets/powermenu.scss"; -@import "./widgets/system-monitor.scss"; -@import "./widgets/wallpaper-picker.scss"; -@import "./widgets/workspaces.scss"; diff --git a/config/ags/style/vars.scss b/config/ags/style/vars.scss deleted file mode 100644 index de905821..00000000 --- a/config/ags/style/vars.scss +++ /dev/null @@ -1,19 +0,0 @@ -$window_margin: 2px 2px 1px 2px ; -$border_radius: 6px 6px 6px 6px ; -$bar_border_radius: 0px 0px 0px 0px ; -$bar_margin: 1px 1px 1px 1px ; -$workspace_active_width: 0px; -$dark_mode: true; -$osd_regular_margin: 0px 12px 60px 0px; -$osd_progress_margin: 12px 12px 2px 12px; -$bar_opacity: 0; -$bar_button_opacity: 0.6; -$panel_button_padding: 4px 8px 4px 8px; -$bar_padding: 1px 1px 1px 1px ; -$bar_shadow: false; -$bar_button_shadow: false; -$bar_button_border_radius: 6px 6px 6px 6px ; -$system_monitor_margin: 2px 2px 2px 2px ; -$bar_border: false; -$window_opacity: 1; -$window_border: false; diff --git a/config/ags/style/widgets/applauncher.scss b/config/ags/style/widgets/applauncher.scss deleted file mode 100644 index 4ece135a..00000000 --- a/config/ags/style/widgets/applauncher.scss +++ /dev/null @@ -1,5 +0,0 @@ -.applauncher__container { - .entry-box { - margin: 10px; - } -} diff --git a/config/ags/style/widgets/audio-popup.scss b/config/ags/style/widgets/audio-popup.scss deleted file mode 100644 index ed3abd70..00000000 --- a/config/ags/style/widgets/audio-popup.scss +++ /dev/null @@ -1,58 +0,0 @@ -.audio__container { - padding: 5px; - - .volume { - margin: 5px; - } - - .microphone { - margin: 5px; - } - - .app-mixer { - scale { - margin-top: 4px; - - trough { - min-height: 10px; - } - } - } - - .menu { - min-width: 300px; - border-radius: $border_radius; - margin: 5px; - - .content.vertical { - >*:first-child>* { - &:last-child { - margin-bottom: 8px; - } - } - - >button { - image { - margin-right: 6px; - } - - margin: 8px 10px; - margin-bottom: 0px; - border: 1px solid transparentize($color: $on_background, $amount: 0.8); - box-shadow: unset; - padding: 6px; - border-radius: divide-each($border_radius, 2); - } - } - } - - .arrow { - padding: 3px; - border-radius: divide-each($border_radius, 2); - background-color: $on_secondary; - - &:hover { - background-color: $primary_container; - } - } -} diff --git a/config/ags/style/widgets/bar.scss b/config/ags/style/widgets/bar.scss deleted file mode 100644 index e3953d2b..00000000 --- a/config/ags/style/widgets/bar.scss +++ /dev/null @@ -1,21 +0,0 @@ -.bar__container { - background-color: transparentize($color: $background, - $amount: 1 - $bar_opacity ); - margin: $bar_margin; - border-radius: $bar_border_radius; - box-shadow: if($bar_shadow, 2px 2px 5px rgba(0, 0, 0, 0.3), none); - padding: $bar_padding; - border: if($bar_border, 1px solid transparentize($on_background, 0.7), none); - - .start { - .panel-button:first-child { - // margin-left: nth($list: $bar_padding, $n: 2); - } - } - - .end { - .panel-button:last-child { - // margin-right: nth($list: $bar_padding, $n: 4); - } - } -} diff --git a/config/ags/style/widgets/battery-popup.scss b/config/ags/style/widgets/battery-popup.scss deleted file mode 100644 index 6522838f..00000000 --- a/config/ags/style/widgets/battery-popup.scss +++ /dev/null @@ -1,52 +0,0 @@ -.battery-popup__container { - min-width: 300px; - padding: 10px; - - .battery-info__container { - .percent { - font-size: 30px; - color: $on_primary; - font-weight: 600; - margin-left: 10px; - } - - levelbar { - trough { - min-height: 50px; - } - } - - .time-remaining { - color: $on_background; - font-size: 13px; - margin-top: 4px; - margin-bottom: 10px; - font-style: italic; - } - } - - .power-profile__container { - label { - font-size: 13px; - font-weight: 600; - margin-bottom: 6px; - } - - .item { - box-shadow: 1px 1px 2px transparentize($color: rgb(0, 0, 0), $amount: 0.7); - border-radius: divide-each($border_radius, 1.5); - color: $on_background; - background-color: $on_secondary; - min-height: 24px; - - &:hover { - background-color: $primary_container; - } - - &.active { - background-color: $primary; - color: $background; - } - } - } -} diff --git a/config/ags/style/widgets/control-center.scss b/config/ags/style/widgets/control-center.scss deleted file mode 100644 index b19e5eaa..00000000 --- a/config/ags/style/widgets/control-center.scss +++ /dev/null @@ -1,90 +0,0 @@ -.control-center__container { - .brightness-box { - padding: 10px; - } - - .notifications__container { - padding: 10px 0px; - - .placeholder { - image { - font-size: 24px; - } - - label { - margin-top: 6px; - font-size: 14px; - } - } - - .header { - padding: 0px 10px; - padding-right: 13px; - margin-bottom: 5px; - - label { - font-size: 18px; - font-weight: 600; - } - - button { - border-radius: divide-each($border_radius, 2); - background-color: $on_secondary; - padding: 10px; - - &:hover { - background-color: $primary_container; - } - } - } - - .notification { - margin: 5px 10px; - margin-right: 13px; - background-color: $on_secondary; - - .actions button { - background-color: transparentize($color: $on_background, $amount: 0.9); - - &:hover { - background-color: $primary_container; - } - } - - .content { - .description { - min-width: 235px; - } - } - } - } - - .qs-buttons { - padding: 10px; - - .qs-button { - background-color: $on_secondary; - color: $on_background; - padding: 6px 4px; - - &:active { - background-color: $primary; - color: $on_background; - } - - &:hover { - background-color: $primary_container; - } - - .label { - font-weight: 500; - font-size: 12px; - } - - &.active { - background-color: $primary; - color: $background; - } - } - } -} diff --git a/config/ags/style/widgets/datemenu.scss b/config/ags/style/widgets/datemenu.scss deleted file mode 100644 index 79349d73..00000000 --- a/config/ags/style/widgets/datemenu.scss +++ /dev/null @@ -1,27 +0,0 @@ -.datemenu__container { - padding: 10px; - - .clock { - font-size: 35px; - font-weight: 500; - } - - .date { - font-size: 18px; - font-weight: 400; - margin-bottom: 12px; - } - - calendar { - font-weight: 500; - border: unset; - border-radius: unset; - - &:selected { - background-color: $primary; - border-radius: 0; - color: $background; - border-radius: 6px; - } - } -} diff --git a/config/ags/style/widgets/media.scss b/config/ags/style/widgets/media.scss deleted file mode 100644 index c813fbe2..00000000 --- a/config/ags/style/widgets/media.scss +++ /dev/null @@ -1,46 +0,0 @@ -.media__container { - .player { - margin-top: 0px; - padding: 10px; - - scale.position { - margin-bottom: 6px; - - trough { - min-height: 15px; - } - } - - .title { - font-size: 16px; - font-weight: 600; - } - - .artist { - font-size: 14px; - } - - .img { - min-width: 100px; - min-height: 100px; - background-size: cover; - background-position: center; - border-radius: $border_radius; - margin-right: 1em; - } - - .position { - font-weight: 600; - } - - .length { - font-weight: 600; - } - - button { - padding: 4px; - box-shadow: none; - border-radius: divide-each($border_radius, 2); - } - } -} diff --git a/config/ags/style/widgets/network-popup.scss b/config/ags/style/widgets/network-popup.scss deleted file mode 100644 index 2df99a1d..00000000 --- a/config/ags/style/widgets/network-popup.scss +++ /dev/null @@ -1,4 +0,0 @@ -.network-info__container { - padding: 10px; - min-width: 350px; -} diff --git a/config/ags/style/widgets/network-speed.scss b/config/ags/style/widgets/network-speed.scss deleted file mode 100644 index 71b04de3..00000000 --- a/config/ags/style/widgets/network-speed.scss +++ /dev/null @@ -1,17 +0,0 @@ -.network-speed { - font-weight: 600; - // margin-left: 3px; - - .label { - font-size: 10px; - - &.vert { - font-size: 9px; - } - } - - .unit { - font-size: 8px; - margin-right: 3px; - } -} diff --git a/config/ags/style/widgets/notifications.scss b/config/ags/style/widgets/notifications.scss deleted file mode 100644 index 731c9793..00000000 --- a/config/ags/style/widgets/notifications.scss +++ /dev/null @@ -1,85 +0,0 @@ -.notification { - box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); - margin: $window_margin; - margin-bottom: 6px; - border-radius: $border-radius; - background-color: $background_color; - color: $on_background; - - &:hover button.close-button { - background-color: $primary_container; - } - - &.critical { - box-shadow: 0.9em 0.9em $error; - } - - button.close-button { - box-shadow: unset; - margin-top: 0.2em; - margin-left: 0.5em; - min-width: 1.2em; - min-height: 1.2em; - - image { - font-size: 16px; - } - - &:hover { - background-color: $primary_container; - } - } - - .content { - margin: 0.7em; - - .title { - font-size: 15px; - font-weight: 600; - } - - .time { - font-size: 15px; - font-weight: 600; - color: transparentize($on_background, 0.2); - } - - .description { - min-width: 300px; - margin-top: 0.5em; - font-size: 0.9em; - font-style: italic; - color: transparentize($on_background, 0.2); - } - - .icon { - margin-right: 10px; - } - } -} - -.actions { - margin: 0.7em; - margin-bottom: 0.7em; - margin-top: 5px; - - button { - border-radius: divide-each($border_radius, 1.7); - padding: 4px; - margin: 0px 6px; - background-color: $background; - font-size: 1.2em; - - &:hover { - background-color: $primary_container; - } - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - } -} diff --git a/config/ags/style/widgets/osd.scss b/config/ags/style/widgets/osd.scss deleted file mode 100644 index 65fa8a2b..00000000 --- a/config/ags/style/widgets/osd.scss +++ /dev/null @@ -1,36 +0,0 @@ -.osd { - background-color: $background_color; - border-radius: divide-each($border_radius, .5); - - &.regular { - box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); - margin: $osd_regular_margin; - min-width: 90px; - padding: 8px; - color: $on_background; - - label { - font-weight: 600; - } - } - - &.progress { - box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); - margin: $osd_progress_margin; - padding: 4px; - - .icon { - color: $background; - } - - .fill { - background-color: $primary; - border-radius: divide-each($border_radius, 1.5); - } - } - - .progress { - background-color: transparentize($color: $on_secondary, $amount: 0.3); - border-radius: divide-each($border_radius, 1.5); - } -} diff --git a/config/ags/style/widgets/overview.scss b/config/ags/style/widgets/overview.scss deleted file mode 100644 index 03d3720b..00000000 --- a/config/ags/style/widgets/overview.scss +++ /dev/null @@ -1,139 +0,0 @@ -.overview-window { - margin-top: 2.727rem; -} - -.overview-search-box { - @include element_decel; - @include large-rounding; - @include elevation-border; - @include elevation2; - min-width: 13.636rem; - min-height: 3.409rem; - padding: 0rem 1.364rem; - padding-right: 2.864rem; - background-color: $background; - color: $onBackground; - - selection { - background-color: $secondary; - color: $onSecondary; - } - - caret-color: transparent; -} - -.overview-search-box-extended { - min-width: 25.909rem; - caret-color: $onSecondaryContainer; -} - -.overview-search-prompt { - color: $subtext; -} - -.overview-search-icon { - margin: 0rem 1.023rem; -} - -.overview-search-prompt-box { - margin-left: -18.545rem; - margin-right: $elevation_margin + 0.068rem; -} - -.overview-search-icon-box { - margin-left: -18.545rem; - margin-right: $elevation_margin + 0.068rem; -} - -.overview-search-results { - // min-height: 2.813rem; - // min-height: 37.5rem; - @include large-rounding; - @include elevation-border; - @include elevation2; - min-width: 28.773rem; - padding: 0.682rem; - background-color: $layer0; - color: $onLayer0; -} - -.overview-search-results-icon { - margin: 0rem 0.682rem; - font-size: 2.386rem; - min-width: 2.386rem; - min-height: 2.386rem; -} - -.overview-search-results-txt { - margin-right: 0.682rem; -} - -.overview-search-results-txt-cmd { - margin-right: 0.682rem; - @include techfont; - font-size: 1.227rem; -} - -.overview-search-result-btn { - @include normal-rounding; - padding: 0.341rem; - min-width: 2.386rem; - min-height: 2.386rem; - - caret-color: transparent; -} - -.overview-search-result-btn:hover, -.overview-search-result-btn:focus { - background-color: $hovercolor; -} - -.overview-search-result-btn:active { - background-color: $activecolor; -} - -.overview-tasks { - @include large-rounding; - @include elevation-border; - @include elevation2; - padding: 0.341rem; - background-color: $background; - color: $onBackground; -} - -.overview-tasks-workspace { - @include normal-rounding; - // @include elevation-border; - margin: 0.341rem; - background-color: $layer1; -} - -.overview-tasks-workspace-number { - @include mainfont; - color: $onSurfaceVariant; -} - -.overview-tasks-window { - @include normal-rounding; - @include menu_decel; - background-color: transparentize($layer3, 0.2); - color: $onSurface; - border: 0.068rem solid $surfaceContainerHighest; -} - -.overview-tasks-window:hover, -.overview-tasks-window:focus { - background-color: transparentize($secondaryContainer, 0.3); -} - -.overview-tasks-window:active { - background-color: transparentize($secondaryContainer, 0); -} - -.overview-tasks-window-selected { - background-color: transparentize($secondaryContainer, 0.3); -} - -.overview-tasks-window-dragging { - opacity: 0.2; -} diff --git a/config/ags/style/widgets/powermenu.scss b/config/ags/style/widgets/powermenu.scss deleted file mode 100644 index 0c622496..00000000 --- a/config/ags/style/widgets/powermenu.scss +++ /dev/null @@ -1,74 +0,0 @@ -.powermenu__container { - padding: 10px; - - button { - background-color: $on_secondary; - - &:focus { - background-color: $primary; - color: $on_primary; - - &:hover { - background-color: $primary; - color: $primary_container; - } - } - - &:hover { - background-color: $primary_container; - } - - .system-button { - border-radius: $border_radius; - padding: 25px; - - image { - font-size: 50px; - } - - label { - margin-top: 6px; - } - } - } -} - -.verification__container { - padding: 10px; - - .text-box { - .title { - font-size: 28px; - font-weight: 600; - } - - .desc { - margin-top: 4px; - font-size: 18px; - font-weight: 500; - } - } - - .buttons { - margin-top: 10px; - - button { - background-color: $on_secondary; - padding: 10px 40px; - - &:focus { - background-color: $primary; - color: $on_primary; - - &:hover { - background-color: $primary; - color: $primary_container; - } - } - - &:hover { - background-color: $primary_container; - } - } - } -} diff --git a/config/ags/style/widgets/system-monitor.scss b/config/ags/style/widgets/system-monitor.scss deleted file mode 100644 index f3d45192..00000000 --- a/config/ags/style/widgets/system-monitor.scss +++ /dev/null @@ -1,89 +0,0 @@ -.system-monitor__container { - padding: 10px; - padding-top: 0px; - min-width: 220px; - - border-radius: $border_radius; - margin: $system_monitor_margin; - - .day-dots { - .fill { - min-height: 15px; - min-width: 15px; - border-radius: divide-each($border_radius, 1.5); - background-color: $primary; - border: solid 1px $primary; - } - - .empty { - min-width: 15px; - min-height: 15px; - border-radius: divide-each($border_radius, 1.5); - border: solid 1px $primary; - } - } - - .day { - font-size: 50px; - font-family: "Roboto Condensed"; - font-weight: 600; - color: $primary; - margin-bottom: 8px; - } - - .day-number { - font-size: 30px; - font-family: "Roboto Condensed"; - font-weight: 600; - color: transparentize($color: $on_background, $amount: 0.2); - } - - .month { - font-size: 28px; - font-family: "Dancing Script"; - color: transparentize($color: $on_background, $amount: 0.2); - } - - .cpu-box { - min-width: 120px; - } - - .label { - font-size: 14px; - color: $on_background; - } - - separator { - min-height: 2px; - background-color: $primary; - } - - .value { - font-weight: 600; - font-size: 16px; - color: $on_background; - } - - .progress { - min-width: 55px; - min-height: 55px; - font-size: 8px; - margin: 4px; - background-color: $on_secondary; - color: $primary; - - box { - min-height: 55px; - min-width: 55px; - background-color: $on_secondary; - margin: 15px; - border-radius: 99px; - } - - image { - font-size: 16px; - // margin: 5px; - // margin-left: 6px; - } - } -} diff --git a/config/ags/style/widgets/systray.scss b/config/ags/style/widgets/systray.scss deleted file mode 100644 index 27a80494..00000000 --- a/config/ags/style/widgets/systray.scss +++ /dev/null @@ -1,6 +0,0 @@ -.systray__container { - .entry-box { - margin: 10px; - } -} - diff --git a/config/ags/style/widgets/tray.scss b/config/ags/style/widgets/tray.scss deleted file mode 100644 index 0b12dc61..00000000 --- a/config/ags/style/widgets/tray.scss +++ /dev/null @@ -1,11 +0,0 @@ -.tray__container { - .entry-box { - margin: 10px; - } - &:selected { - background-color: $primary; - border-radius: 0; - color: $background; - border-radius: 6px; - } -} diff --git a/config/ags/style/widgets/wallpaper-picker.scss b/config/ags/style/widgets/wallpaper-picker.scss deleted file mode 100644 index 4c805536..00000000 --- a/config/ags/style/widgets/wallpaper-picker.scss +++ /dev/null @@ -1,127 +0,0 @@ -.wallpaper-picker__container { - .item { - padding: 10px; - } - - .entry-box { - margin: 10px; - margin-right: 0px; - } - - .path { - margin-left: 10px; - font-size: 12px; - font-style: italic; - } - - .folder-button { - background-color: $on_secondary; - padding: 0px 10px; - margin: 10px 0px; - margin-right: 10px; - - &:hover { - background-color: $primary_container; - } - } -} - -popover { - background-color: $background; - color: $on_background; - - >*>* { - padding: 6px; - } -} - -dialog { - background-color: $background_color; - color: $on_background; - - .dialog-action-box { - background-color: $background_color; - - button { - padding: 10px; - margin-right: 5px; - margin-left: 5px; - border: 1px solid $primary; - } - } - - scrolledwindow { - treeview { - padding: 6px; - color: $on_background; - - &:disabled { - color: transparentize($color: $on_background, $amount: 0.5); - } - - &:selected { - background-color: $primary; - color: $background; - } - - button { - // padding: 10px; - padding: 10px; - } - } - } - - #pathbarbox { - stack { - .popup.toggle { - padding: 10px; - } - - .linked.path-bar { - button { - background-color: transparentize($color: $background, $amount: 0.2); - border-left: 0.25px solid transparentize($color: $on_background, $amount: 0.8); - border-right: 0.25px solid transparentize($color: $on_background, $amount: 0.4); - color: $on_background; - padding: 10px; - - &:checked { - background-color: transparentize($color: $primary, $amount: 0.2); - color: $background; - } - - &:hover { - background-color: transparentize($color: $primary_container, - $amount: 0.3); - color: $on_background; - } - } - } - } - } - - placessidebar { - background-color: $background_color; - - row { - padding: 10px; - - &:selected { - background-color: $primary; - color: $background; - - &:hover { - color: $on_background; - } - } - - &:hover { - background-color: $primary_container; - } - - image { - padding-right: 10px; - } - } - } -} diff --git a/config/ags/style/widgets/workspaces.scss b/config/ags/style/widgets/workspaces.scss deleted file mode 100644 index c4c14a53..00000000 --- a/config/ags/style/widgets/workspaces.scss +++ /dev/null @@ -1,60 +0,0 @@ -.workspace__container { - background-color: transparentize(if($dark_mode, $background, $on_secondary), - 1 - $bar_button_opacity ); - color: $on_background; - // margin-top: nth($list: $bar_padding, $n: 1); - // margin-bottom: nth($list: $bar_padding, $n: 3); - // margin-right: 3px; - border-radius: $bar_button_border_radius; - padding: $panel_button_padding; - box-shadow: if($bar_button_shadow, 1px 1px 2px rgba(0, 0, 0, 0.4), none); - - .workspace-button { - min-height: 5px; - min-width: 5px; - border: solid 2px $on_background; - border-radius: $bar_button_border_radius; - padding: 2px; - - .fill { - border-radius: divide-each($bar_button_border_radius, 2); - } - - &:hover { - border-color: $primary; - } - - &.active { - border-color: $primary; - - .fill { - &.hort { - min-width: $workspace_active_width; - } - - &.vert { - min-width: 0px; - min-height: $workspace_active_width; - } - } - } - - &.occupied { - &:hover { - .fill { - background-color: $primary; - } - } - - .fill { - background-color: $on_background; - } - - &.active { - .fill { - background-color: $primary; - } - } - } - } -} diff --git a/config/ags/svg/New Folder/brightness-onPrimary.svg b/config/ags/svg/New Folder/brightness-onPrimary.svg new file mode 100644 index 00000000..b0872237 --- /dev/null +++ b/config/ags/svg/New Folder/brightness-onPrimary.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/config/ags/svg/New Folder/dark-onPrimary.svg b/config/ags/svg/New Folder/dark-onPrimary.svg new file mode 100644 index 00000000..eb5c96e6 --- /dev/null +++ b/config/ags/svg/New Folder/dark-onPrimary.svg @@ -0,0 +1,16 @@ + + + + dark-mode-solid + + + + + + + + + + + + \ No newline at end of file diff --git a/config/ags/svg/brightness-onPrimary.svg b/config/ags/svg/brightness-onPrimary.svg new file mode 100644 index 00000000..eb353de7 --- /dev/null +++ b/config/ags/svg/brightness-onPrimary.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/config/ags/svg/dark-onPrimary.svg b/config/ags/svg/dark-onPrimary.svg new file mode 100644 index 00000000..e7590205 --- /dev/null +++ b/config/ags/svg/dark-onPrimary.svg @@ -0,0 +1,12 @@ + + + + + + + + + + dark-mode + + \ No newline at end of file diff --git a/config/ags/tsconfig.json b/config/ags/tsconfig.json new file mode 100644 index 00000000..cf91e97c --- /dev/null +++ b/config/ags/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": [ + "ES2022" + ], + "allowJs": true, + "checkJs": true, + "strict": true, + "noImplicitAny": false, + "baseUrl": ".", + "typeRoots": [ + "./types" + ], + "skipLibCheck": true, + "moduleResolution": "Node", + "declaration": true, + "emitDeclarationOnly": true, + "allowImportingTsExtensions": true + } +} \ No newline at end of file diff --git a/config/ags/types b/config/ags/types new file mode 120000 index 00000000..a8e3f041 --- /dev/null +++ b/config/ags/types @@ -0,0 +1 @@ +/usr/share/com.github.Aylur.ags/types \ No newline at end of file diff --git a/config/ags/vars.js b/config/ags/vars.js deleted file mode 100644 index d1664c6c..00000000 --- a/config/ags/vars.js +++ /dev/null @@ -1,200 +0,0 @@ -import GLib from "gi://GLib"; -import Conf from "./services/configuration.js"; -import { cpWallpaper } from "./functions/wallpaper.js"; -import { setTheme } from "./functions/theme/init.js"; -import { setScssVariable } from "./functions/theme/ags.js"; -import { sendBatch } from "./functions/utils.js"; -import { setGapsOut } from "./functions/theme/hyprland.js"; -import { isVertical } from "./functions/utils.js"; -import setGtk from "./functions/theme/gtk.js"; - -export const HOME = Utils.HOME; - -export const clock = Variable(GLib.DateTime.new_now_local(), { - poll: [1000, () => GLib.DateTime.new_now_local()], -}); - -export const capsLockState = Variable( - Utils.exec(`brightnessctl -d input3::capslock g`), -); - -const divide = ([total, free]) => free / total; - -export const cpu = Variable(0, { - poll: [ - 2000, - "top -b -n 1", - (out) => - divide([ - 100, - out - .split("\n") - .find((line) => line.includes("Cpu(s)")) - .split(/\s+/)[1] - .replace(",", "."), - ]), - ], -}); - -export const ram = Variable(0, { - poll: [ - 2000, - "free", - (out) => - divide( - out - .split("\n") - .find((line) => line.includes("Mem:")) - .split(/\s+/) - .splice(1, 2), - ), - ], -}); - -export const configs = { - wallpaper: { - folder: Conf("wallpaper.folder", () => null, { home: HOME }), - current: Conf("wallpaper.current", (self) => { - cpWallpaper(self.value); - }), - }, - theme: { - dark_mode: Conf("theme.dark_mode", setTheme), - border_radius: Conf("theme.border_radius", (self) => { - setScssVariable({ - key: "border_radius", - value: self.value, - }); - sendBatch([`decoration:rounding ${self.value.split(",")[0].trim()}`]); - }), - window: { - margin: Conf("theme.window.margin", (self) => { - setScssVariable({ - key: "window_margin", - value: self.value, - }); - setGapsOut(); - }), - opacity: Conf("theme.window.opacity", (self) => { - setScssVariable({ - key: "window_opacity", - value: self.value, - need_format: false, - }); - setGtk(); - }), - border: Conf("theme.window.border", (self) => { - setScssVariable({ - key: "window_border", - value: self.value, - need_format: false, - }); - }), - }, - bar: { - position: Conf("theme.bar.position", (self) => { - sendBatch([ - ...App.windows.flatMap( - (win) => - `layerrule animation ${win.animation === "slide top" ? `slide ${self.value}` : win.animation}, ${win.name}`, - ), - `animation workspaces,1,7,menu_decel,${isVertical(self.value) ? `slidevert` : "slide"}`, - ]); - setGapsOut(); - setScssVariable({ bar_pos: self.value }); - }), - border: Conf("theme.bar.border", (self) => { - setScssVariable({ - key: "bar_border", - value: self.value, - need_format: false, - }); - }), - opacity: Conf("theme.bar.opacity", (self) => { - setScssVariable({ - key: "bar_opacity", - value: self.value, - need_format: false, - }); - }), - button_opacity: Conf("theme.bar.button_opacity", (self) => { - setScssVariable({ - key: "bar_button_opacity", - value: self.value, - need_format: false, - }); - }), - shadow: Conf("theme.bar.shadow", (self) => { - setScssVariable({ - key: "bar_shadow", - value: self.value, - need_format: false, - }); - }), - button_padding: Conf("theme.bar.button_padding", (self) => { - setScssVariable({ key: "panel_button_padding", value: self.value }); - }), - button_spacing: Conf("theme.bar.button_spacing"), - button_shadow: Conf("theme.bar.button_shadow", (self) => { - setScssVariable({ - key: "bar_button_shadow", - value: self.value, - need_format: false, - }); - }), - button_border_radius: Conf("theme.bar.button_border_radius", (self) => { - setScssVariable({ - key: "bar_button_border_radius", - value: self.value, - }); - }), - margin: Conf("theme.bar.margin", (self) => { - setScssVariable({ key: "bar_margin", value: self.value }); - }), - padding: Conf("theme.bar.padding", (self) => { - setScssVariable({ key: "bar_padding", value: self.value }); - }), - border_radius: Conf("theme.bar.border_radius", (self) => { - setScssVariable({ key: "bar_border_radius", value: self.value }); - }), - launcher_icon: Conf("theme.bar.launcher_icon"), - workspace_active_width: Conf( - "theme.bar.workspace_active_width", - (self) => { - setScssVariable({ - key: "workspace_active_width", - value: self.value, - need_format: true, - four_values: false, - }); - }, - ), - }, - }, - osd: { - regular: { - position: Conf("osd.regular.position"), - vertical: Conf("osd.regular.vertical"), - margin: Conf("osd.regular.margin", (self) => { - setScssVariable({ key: "osd_regular_margin", value: self.value }); - }), - capslock: Conf("osd.regular.capslock"), - mic: Conf("osd.regular.mic"), - }, - progress: { - position: Conf("osd.progress.position"), - vertical: Conf("osd.progress.vertical"), - margin: Conf("osd.progress.margin", (self) => { - setScssVariable({ key: "osd_progress_margin", value: self.value }); - }), - brightness: Conf("osd.progress.brightness"), - volume: Conf("osd.progress.volume"), - }, - }, - system_monitor: { - position: Conf("system_monitor.position"), - margin: Conf("system_monitor.margin", (self) => { - setScssVariable("system_monitor_margin", self.value); - }), - }, -}; diff --git a/config/ags/widget/FileChooserDialog.js b/config/ags/widget/FileChooserDialog.js deleted file mode 100644 index 69bdb7d9..00000000 --- a/config/ags/widget/FileChooserDialog.js +++ /dev/null @@ -1,3 +0,0 @@ -import Gtk from "gi://Gtk"; - -export default Widget.subclass(Gtk.FileChooserDialog); diff --git a/config/ags/widget/PanelButton.js b/config/ags/widget/PanelButton.js deleted file mode 100644 index 20055b97..00000000 --- a/config/ags/widget/PanelButton.js +++ /dev/null @@ -1,27 +0,0 @@ -export default ({ window = "", child, setup, ...rest }) => - Widget.Button({ - child: Widget.Box({ hpack: "center", child }), - setup: (self) => { - let open = false; - - self.toggleClassName("panel-button"); - self.toggleClassName(window); - - self.hook(App, (_, win, visible) => { - if (win !== window) return; - - if (open && !visible) { - open = false; - self.toggleClassName("active", false); - } - - if (visible) { - open = true; - self.toggleClassName("active"); - } - }); - - if (setup) setup(self); - }, - ...rest, - }); diff --git a/config/ags/widget/PopupWindow.js b/config/ags/widget/PopupWindow.js deleted file mode 100644 index e75a6233..00000000 --- a/config/ags/widget/PopupWindow.js +++ /dev/null @@ -1,141 +0,0 @@ -export const Padding = (name) => - Widget.EventBox({ - hexpand: true, - vexpand: true, - can_focus: false, - child: Widget.Box({}), - setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)), - }); - -const Layout = (name, child) => ({ - center: () => - Widget.CenterBox( - {}, - Padding(name), - Widget.CenterBox({ vertical: true }, Padding(name), child, Padding(name)), - Padding(name), - ), - top: () => - Widget.CenterBox( - {}, - Padding(name), - Widget.Box({ vertical: true }, child, Padding(name)), - Padding(name), - ), - right: () => - Widget.Box( - {}, - Padding(name), - Widget.Box( - { - hexpand: false, - vertical: true, - }, - child, - ), - ), - "top-right": () => - Widget.Box( - {}, - Padding(name), - Widget.Box( - { - hexpand: false, - vertical: true, - }, - child, - Padding(name), - ), - ), - "top-center": () => - Widget.Box( - {}, - Padding(name), - Widget.Box( - { - hexpand: false, - vertical: true, - }, - child, - Padding(name), - ), - Padding(name), - ), - "top-left": () => - Widget.Box( - {}, - Widget.Box( - { - hexpand: false, - vertical: true, - }, - child, - Padding(name), - ), - Padding(name), - ), - "bottom-left": () => - Widget.Box( - {}, - Widget.Box( - { - hexpand: false, - vertical: true, - }, - Padding(name), - child, - ), - Padding(name), - ), - "bottom-center": () => - Widget.Box( - {}, - Padding(name), - Widget.Box( - { - hexpand: false, - vertical: true, - }, - Padding(name), - child, - ), - Padding(name), - ), - "bottom-right": () => - Widget.Box( - {}, - Padding(name), - Widget.Box( - { - hexpand: false, - vertical: true, - }, - Padding(name), - child, - ), - ), -}); - -export default ({ - name, - child, - animation = "popin 80%", - layout = "center", - ...props -}) => { - const win = Widget.Window({ - name, - visible: false, - layer: "overlay", - keymode: "exclusive", - anchor: ["top", "bottom", "right", "left"], - child: Layout(name, child)[layout](), - setup: (w) => w.keybind("Escape", () => App.closeWindow(name)), - ...props, - }); - Object.assign(win, { - animation: animation, - }); - - return win; -}; diff --git a/config/ags/widget/ToggleButton.js b/config/ags/widget/ToggleButton.js deleted file mode 100644 index 8436ab6a..00000000 --- a/config/ags/widget/ToggleButton.js +++ /dev/null @@ -1,128 +0,0 @@ -export const opened = Variable(""); - -export const Row = (toggles, menus) => - Widget.Box({ - vertical: true, - children: [ - Widget.Box({ - homogeneous: true, - class_name: "row horizontal", - spacing: 6, - children: toggles.map((w) => w()), - }), - ...menus.map((w) => w()), - ], - }); - -export const Arrow = (name, activate) => { - let deg = 0; - let iconOpened = false; - const icon = Widget.Icon("pan-end-symbolic").hook(opened, () => { - if ( - (opened.value === name && !iconOpened) || - (opened.value !== name && iconOpened) - ) { - const step = opened.value === name ? 10 : -10; - iconOpened = !iconOpened; - for (let i = 0; i < 9; ++i) { - Utils.timeout(15 * i, () => { - deg += step; - icon.setCss(`-gtk-icon-transform: rotate(${deg}deg);`); - }); - } - } - }); - - return Widget.Button({ - child: icon, - class_name: "arrow", - on_clicked: () => { - opened.value = opened.value === name ? "" : name; - if (typeof activate === "function") activate(); - }, - }); -}; - -export const ArrowToggleButton = ({ - name, - icon, - label, - activate, - deactivate, - activateOnArrow = true, - connection: [service, condition], -}) => - Widget.Box({ - class_name: "toggle-button", - setup: (self) => - self.hook(service, () => { - self.toggleClassName("active", condition()); - }), - children: [ - Widget.Button({ - child: Widget.Box({ - hexpand: true, - children: [ - Widget.Icon({ - class_name: "icon", - size: 18, - icon, - }), - Widget.Label({ - class_name: "label", - max_width_chars: 10, - truncate: "end", - label, - }), - ], - }), - on_clicked: () => { - if (condition()) { - deactivate(); - if (opened.value === name) opened.value = ""; - } else { - activate(); - } - }, - }), - Arrow(name, activateOnArrow && activate), - ], - }); - -export const Menu = ({ parentWindowName, name, icon, title, content }) => { - App.connect("window-toggled", (_, name, visible) => { - if (name === parentWindowName && !visible) - Utils.timeout(500, () => (opened.value = "")); - }); - - return Widget.Revealer({ - transition: "slide_down", - reveal_child: opened.bind().as((v) => v === name), - child: Widget.Box({ - class_names: ["menu", name], - vertical: true, - children: [ - Widget.Box({ - class_name: "title-box", - children: [ - Widget.Icon({ - class_name: "icon", - icon, - }), - Widget.Label({ - class_name: "title", - truncate: "end", - label: title, - }), - ], - }), - Widget.Separator(), - Widget.Box({ - vertical: true, - class_name: "content vertical", - children: content, - }), - ], - }), - }); -}; diff --git a/config/ags/widget/applauncher/PanelButton.js b/config/ags/widget/applauncher/PanelButton.js deleted file mode 100644 index d7056c5f..00000000 --- a/config/ags/widget/applauncher/PanelButton.js +++ /dev/null @@ -1,28 +0,0 @@ -import PanelButton from "../PanelButton.js"; -import { WINDOW_NAME } from "./Window.js"; -import { configs } from "../../vars.js"; - -export default () => - PanelButton({ - window: WINDOW_NAME, - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - }, - child: configs.theme.bar.launcher_icon.bind().as((icon) => { - const isGtkIcon = Utils.lookUpIcon(icon); - - if (isGtkIcon) { - return Widget.Icon({ - icon: icon, - hpack: "center", - xalign: 0, - }); - } else { - return Widget.Label({ - label: icon, - hpack: "center", - xalign: 0, - }); - } - }), - }); diff --git a/config/ags/widget/applauncher/Window.js b/config/ags/widget/applauncher/Window.js deleted file mode 100644 index 961a75b2..00000000 --- a/config/ags/widget/applauncher/Window.js +++ /dev/null @@ -1,99 +0,0 @@ -import PopupWindow from "../PopupWindow.js"; -const { query } = await Service.import("applications"); -export const WINDOW_NAME = "applauncher__window"; - -const AppItem = (app) => - Widget.Button({ - class_name: "item", - on_clicked: () => { - App.closeWindow(WINDOW_NAME); - app.launch(); - }, - attribute: { app }, - child: Widget.Box({ - children: [ - Widget.Icon({ - icon: app.icon_name || "", - size: 30, - }), - Widget.Label({ - class_name: "title", - label: app.name, - xalign: 0, - vpack: "center", - truncate: "end", - }), - ], - }), - }); - -const Container = ({ width = 500, height = 500, spacing = 12 }) => { - let applications = query("").map(AppItem); - - const list = Widget.Box({ - vertical: true, - children: applications, - spacing, - }); - - function repopulate() { - applications = query("").map(AppItem); - list.children = applications; - } - - const entry = Widget.Box({ - class_name: "entry-box", - children: [ - Widget.Icon({ icon: "search-symbolic" }), - Widget.Entry({ - hexpand: true, - on_accept: () => { - const results = applications.filter((item) => item.visible); - if (results[0]) { - App.toggleWindow(WINDOW_NAME); - results[0].attribute.app.launch(); - } - }, - on_change: ({ text }) => - applications.forEach((item) => { - item.visible = item.attribute.app.match(text ?? ""); - }), - setup: (self) => - self.hook(App, (_, windowName, visible) => { - if (windowName !== WINDOW_NAME) return; - if (visible) { - self.text = ""; - self.grab_focus(); - } - }), - }), - ], - }); - - return Widget.Box({ - vertical: true, - class_names: ["applauncher__container", "window-content"], - children: [ - entry, - Widget.Scrollable({ - hscroll: "never", - css: `min-width: ${width}px;` + `min-height: ${height}px;`, - child: list, - }), - ], - setup: (self) => - self.hook(App, (_, windowName, visible) => { - if (windowName !== WINDOW_NAME) return; - if (visible) { - repopulate(); - } - }), - }); -}; - -export default () => - PopupWindow({ - name: WINDOW_NAME, - animation: "popin 80%", - child: Container({ height: 350, width: 350 }), - }); diff --git a/config/ags/widget/audio/PanelButton.js b/config/ags/widget/audio/PanelButton.js deleted file mode 100644 index 4975dfa1..00000000 --- a/config/ags/widget/audio/PanelButton.js +++ /dev/null @@ -1,34 +0,0 @@ -import "../PanelButton.js"; -import PanelButton from "../PanelButton.js"; -import { WINDOW_NAME } from "./Window.js"; -const audio = await Service.import("audio"); - -const icons = { - muted: "audio-volume-muted-symbolic", - low: "audio-volume-low-symbolic", - medium: "audio-volume-medium-symbolic", - high: "audio-volume-high-symbolic", - overamplified: "audio-volume-overamplified-symbolic", -}; - -export default () => - PanelButton({ - window: WINDOW_NAME, - on_scroll_up: () => (audio.speaker.volume += 0.02), - on_scroll_down: () => (audio.speaker.volume -= 0.02), - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - }, - child: Widget.Icon().hook(audio.speaker, (self) => { - const vol = audio.speaker.is_muted ? 0 : audio.speaker.volume; - const { muted, low, medium, high, overamplified } = icons; - const cons = [ - [101, overamplified], - [67, high], - [34, medium], - [1, low], - [0, muted], - ]; - self.icon = cons.find(([n]) => n <= vol * 100)?.[1] || ""; - }), - }); diff --git a/config/ags/widget/audio/Window.js b/config/ags/widget/audio/Window.js deleted file mode 100644 index 55c4b08f..00000000 --- a/config/ags/widget/audio/Window.js +++ /dev/null @@ -1,190 +0,0 @@ -import { icon, layoutPos, sh } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; -import PopupWindow from "../PopupWindow.js"; -import { Arrow, Menu, Row } from "../ToggleButton.js"; -const audio = await Service.import("audio"); -const { bar } = configs.theme; - -export const WINDOW_NAME = "audio__window"; - -const VolumeIndicator = (type = "speaker") => - Widget.Icon({ - icon: audio[type] - .bind("icon_name") - .as((i) => icon(i || "", "microphone-sensitivity-high-symbolic")), - tooltipText: audio[type] - .bind("volume") - .as((vol) => `Volume: ${Math.floor(vol * 100)}%`), - size: 18, - }); - -const VolumeSlider = (type = "speaker") => - Widget.Slider({ - hexpand: true, - draw_value: false, - on_change: ({ value, dragging }) => { - if (dragging) { - audio[type].volume = value; - audio[type].is_muted = false; - } - }, - value: audio[type].bind("volume"), - class_name: audio[type].bind("is_muted").as((m) => (m ? "muted" : "")), - }); - -export const Volume = () => - Widget.Box({ - class_name: "volume", - spacing: 6, - children: [ - VolumeIndicator("speaker"), - VolumeSlider("speaker"), - Widget.Box({ - vpack: "center", - child: Arrow("sink-selector"), - }), - Widget.Box({ - vpack: "center", - child: Arrow("app-mixer"), - visible: audio.bind("apps").as((a) => a.length > 0), - }), - ], - }); - -export const Microphone = () => - Widget.Box({ - class_name: "microphone", - visible: audio.bind("recorders").as((a) => a.length > 0), - spacing: 6, - children: [VolumeIndicator("microphone"), VolumeSlider("microphone")], - }); - -const MixerItem = (stream) => - Widget.Box( - { - hexpand: true, - class_name: "mixer-item horizontal", - }, - Widget.Icon({ - tooltip_text: stream.bind("name").as((n) => n || ""), - icon: stream.bind("name").as((n) => { - return Utils.lookUpIcon(n || "") ? n || "" : "audio-x-generic-symbolic"; - }), - }), - Widget.Box( - { vertical: true }, - Widget.Label({ - xalign: 0, - truncate: "end", - max_width_chars: 18, - label: stream.bind("description").as((d) => d || ""), - }), - Widget.Slider({ - hexpand: true, - draw_value: false, - value: stream.bind("volume"), - on_change: ({ value }) => (stream.volume = value), - }), - ), - ); - -const SinkItem = (stream) => - Widget.Button({ - hexpand: true, - on_clicked: () => (audio.speaker = stream), - child: Widget.Box({ - children: [ - Widget.Icon({ - icon: icon(stream.icon_name || "", "audio-x-generic-symbolic"), - tooltip_text: stream.icon_name || "", - }), - Widget.Label( - (stream.description || "").split(" ").slice(0, 4).join(" "), - ), - Widget.Icon({ - icon: "audio-x-generic-symbolic", - hexpand: true, - hpack: "end", - visible: audio.speaker.bind("stream").as((s) => s === stream.stream), - }), - ], - }), - }); - -const SettingsButton = () => - Widget.Button({ - on_clicked: () => { - sh("pavucontrol"); - }, - hexpand: true, - child: Widget.Box({ - children: [ - Widget.Icon("emblem-system-symbolic"), - Widget.Label("Settings"), - ], - }), - }); - -export const AppMixer = () => - Menu({ - parentWindowName: WINDOW_NAME, - name: "app-mixer", - icon: "mixer-symbolic", - title: "App Mixer", - content: [ - Widget.Box({ - vertical: true, - class_name: "vertical mixer-item-box", - children: audio.bind("apps").as((a) => a.map(MixerItem)), - }), - Widget.Separator(), - SettingsButton(), - ], - }); - -export const SinkSelector = () => - Menu({ - name: "sink-selector", - parentWindowName: WINDOW_NAME, - icon: "audio-headphones-symbolic", - title: "Sink Selector", - content: [ - Widget.Box({ - vertical: true, - children: audio.bind("speakers").as((a) => a.map(SinkItem)), - }), - Widget.Separator(), - SettingsButton(), - ], - }); - -const Container = () => - Widget.Box({ - class_names: ["audio__container", "window-content"], - spacing: 8, - vertical: true, - children: [ - Row([Volume], [AppMixer, SinkSelector]), - Widget.Separator({ - visible: audio.bind("recorders").as((a) => a.length > 0), - }), - Microphone(), - ], - }); - -const AudioWindow = () => - PopupWindow({ - name: WINDOW_NAME, - animation: "slide top", - layout: layoutPos(bar.position.value, "top-right"), - child: Container(), - }); - -export default function() { - App.addWindow(AudioWindow()); - - bar.position.connect("changed", () => { - App.removeWindow(WINDOW_NAME); - App.addWindow(AudioWindow()); - }); -} diff --git a/config/ags/widget/bar/Window.js b/config/ags/widget/bar/Window.js deleted file mode 100644 index 78df9d51..00000000 --- a/config/ags/widget/bar/Window.js +++ /dev/null @@ -1,129 +0,0 @@ -import BatteryPanelButton from "../battery/PanelButton.js"; -import DatePanelButton from "../datemenu/PanelButton.js"; -import NetworkSpeedIndicator from "../network_speed/PanelButton.js"; -import AppLauncherPanelButton from "../applauncher/PanelButton.js"; -import WorkspacesPanelButton from "../workspaces/PanelButton.js"; -import ClientPanelButton from "../client/PanelButton.js"; -import ControlCenterPanelButton from "../control_center/PanelButton.js"; -import ScreenRecordPanelButton from "../screen_record/PanelButton.js"; -import NetworkPanelButton from "../network/PanelButton.js"; -import AudioPanelButton from "../audio/PanelButton.js"; -import Tray from "../tray/tray.js"; -import { configs } from "../../vars.js"; -import { isVertical } from "../../functions/utils.js"; -const hyprland = await Service.import("hyprland"); - -const WINDOW_NAME = "bar__window"; - -const getAnchor = () => ({ - left: ["left", "top", "bottom"], - right: ["right", "top", "bottom"], - top: ["top", "left", "right"], - bottom: ["bottom", "left", "right"], -}); - -const startChildren = () => [ - AppLauncherPanelButton(), - DatePanelButton(), - WorkspacesPanelButton(), -]; - -const start = () => - Widget.Box({ - class_name: "start", - spacing: configs.theme.bar.button_spacing.bind(), - vertical: configs.theme.bar.position.bind().as(isVertical), - // vpack: configs.theme.bar.position - // .bind() - // .as((pos) => (pos === "left" ? "end" : "fill")), - vexpand: true, - - // children: configs.theme.bar.position - // .bind() - // .as((pos) => - // pos === "left" ? startChildren().reverse() : startChildren(), - // ), - children: startChildren(), - }); - -const center = () => - Widget.Box({ - children: [ClientPanelButton()], - vertical: configs.theme.bar.position.bind().as(isVertical), - }); - -const endChildren = () => [ - Tray(), - ScreenRecordPanelButton(), - NetworkSpeedIndicator(), - NetworkPanelButton(), - AudioPanelButton(), - BatteryPanelButton(), - ControlCenterPanelButton(), -]; - -const end = () => - Widget.Box({ - class_name: "end", - spacing: configs.theme.bar.button_spacing.bind(), - hpack: "end", - // vpack: configs.theme.bar.position - // .bind() - // .as((pos) => (pos === "left" ? "start" : "end")), - vpack: "end", - vertical: configs.theme.bar.position.bind().as(isVertical), - children: endChildren(), - // children: configs.theme.bar.position - // .bind() - // .as((pos) => (pos === "left" ? endChildren().reverse() : endChildren())), - }); - -const BarWindow = () => { - const win = Widget.Window({ - name: "bar__window", - exclusivity: "exclusive", - visible: false, - anchor: configs.theme.bar.position.bind().as((pos) => getAnchor()[pos]), - // anchor, - child: Widget.CenterBox({ - vertical: configs.theme.bar.position.bind().as(isVertical), - class_names: ["bar__container", "window-content"], - start_widget: start(), - // start_widget: configs.theme.bar.position - // .bind() - // .as((p) => (p === "left" ? end() : start())), - center_widget: center(), - // end_widget: configs.theme.bar.position - // .bind() - // .as((p) => (p === "left" ? start() : end())), - end_widget: end(), - }), - }); - - Object.assign(win, { - animation: `slide`, - }); - - return win; -}; - -export default function() { - App.addWindow(BarWindow()); - Utils.timeout(100, () => { - App.openWindow(WINDOW_NAME); - }); - - configs.theme.bar.position.connect("changed", (self) => { - App.toggleWindow(WINDOW_NAME); - Utils.timeout(300, () => { - App.removeWindow(WINDOW_NAME); - App.addWindow(BarWindow()); - Utils.timeout(100, () => { - hyprland.message( - `keyword layerrule animation slide ${self.value}, ${WINDOW_NAME}`, - ); - App.openWindow(WINDOW_NAME); - }); - }); - }); -} diff --git a/config/ags/widget/battery/PanelButton.js b/config/ags/widget/battery/PanelButton.js deleted file mode 100644 index ba81065d..00000000 --- a/config/ags/widget/battery/PanelButton.js +++ /dev/null @@ -1,32 +0,0 @@ -import { isVertical } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; -import PanelButton from "../PanelButton.js"; -import { WINDOW_NAME } from "./Window.js"; -const battery = await Service.import("battery"); - -export default () => - PanelButton({ - window: WINDOW_NAME, - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - }, - child: Widget.Box({ - class_name: "panel-battery", - vertical: configs.theme.bar.position.bind().as(isVertical), - setup: (self) => { - self.hook(battery, () => { - self.toggleClassName("charging", battery.charging); - }); - }, - spacing: 4, - children: [ - Widget.Icon({ - icon: battery.bind("icon_name"), - }), - Widget.Label({ - label: battery.bind("percent").as((p) => `${Math.round(p)}%`), - visible: battery.bind("charging"), - }), - ], - }), - }); diff --git a/config/ags/widget/battery/Window.js b/config/ags/widget/battery/Window.js deleted file mode 100644 index 69021fc1..00000000 --- a/config/ags/widget/battery/Window.js +++ /dev/null @@ -1,146 +0,0 @@ -import { layoutPos } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; -import PopupWindow from "../PopupWindow.js"; - -const powerProfiles = await Service.import("powerprofiles"); -const battery = await Service.import("battery"); -export const WINDOW_NAME = "battery__window"; -const { bar } = configs.theme; - -function formatTimeUntilCharged(seconds) { - const hours = Math.floor(seconds / 3600); - const minutes = Math.floor((seconds % 3600) / 60); - - let result = ""; - if (hours > 0) { - result += hours + " hour"; - if (hours > 1) result += "s"; - } - if (minutes > 0) { - if (result !== "") result += " "; - result += minutes + " minute"; - if (minutes > 1) result += "s"; - } - - return result; -} -const TimeRemaining = () => - Widget.Label({ - class_name: "time-remaining", - hpack: "start", - label: Utils.merge( - [battery.bind("time-remaining"), battery.bind("charging")], - (tr, charging) => { - const hoursMinutes = formatTimeUntilCharged(tr); - - if (charging) { - return hoursMinutes === "" - ? "Charging..." - : `${hoursMinutes} until fully charged`; - } else { - return hoursMinutes === "" - ? "Not charging" - : `About ${hoursMinutes} left`; - } - }, - ), - }); - -const Item = (profile) => - Widget.Button({ - class_name: "item", - on_clicked: () => { - powerProfiles.active_profile = profile; - }, - setup: (self) => { - self.hook(powerProfiles, (btn) => { - btn.toggleClassName("active", powerProfiles.active_profile == profile); - }); - }, - child: Widget.Box({ - hexpand: true, - spacing: 6, - vpack: "center", - hpack: "center", - children: [ - Widget.Icon({ icon: `power-profile-${profile}-symbolic`, size: 16 }), - ], - }), - }); - -const PowerProfileContainer = () => - Widget.Box({ - vertical: true, - class_name: "power-profile__container", - children: [ - Widget.Label({ - hpack: "start", - label: "Power Profile", - }), - Widget.Box({ - spacing: 6, - vertical: false, - homogeneous: true, - setup: (self) => { - self.hook(powerProfiles, (box) => { - box.children = powerProfiles.profiles.map((profile) => - Item(profile.Profile), - ); - }); - }, - }), - ], - }); - -const PercentLabel = () => - Widget.Box({ - halign: "start", - children: [ - Widget.Label({ - class_name: "percent", - label: battery.bind("percent").as((p) => `${Math.round(p)}%`), - }), - ], - }); - -const LevelBar = () => - Widget.Overlay({ - child: Widget.LevelBar({ - bar_mode: "discrete", - max_value: 10, - value: battery.bind("percent").as((p) => p / 10), - }), - overlays: [PercentLabel()], - }); - -const BatteryInfo = () => - Widget.Box({ - class_name: "battery-info__container", - vertical: true, - children: [LevelBar(), TimeRemaining()], - }); - -const Container = () => - Widget.Box({ - class_names: ["battery-popup__container", "window-content"], - vertical: true, - hexpand: false, - children: [BatteryInfo(), PowerProfileContainer()], - }); - -const BatteryWindow = () => - PopupWindow({ - name: WINDOW_NAME, - animation: "slide top", - layout: layoutPos(bar.position.value, "top-right"), - child: Container(), - }); - -export default function() { - App.addWindow(BatteryWindow()); - - bar.position.connect("changed", () => { - App.removeWindow(WINDOW_NAME); - App.addWindow(BatteryWindow()); - }); -} diff --git a/config/ags/widget/client/PanelButton.js b/config/ags/widget/client/PanelButton.js deleted file mode 100644 index 5817d84b..00000000 --- a/config/ags/widget/client/PanelButton.js +++ /dev/null @@ -1,46 +0,0 @@ -import { icon } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; -import PanelButton from "../PanelButton.js"; - -const hyprland = await Service.import("hyprland"); -const apps = await Service.import("applications"); - -const ClientIcon = () => - Widget.Icon({ - icon: hyprland.active.bind("client").as((client) => { - const app = apps.list.find((app) => app.match(client.class)); - return icon( - (client.class === "" ? "desktop" : app?.icon_name) + "-symbolic", - app?.icon_name, - ); - }), - }); - -export default () => - PanelButton({ - tooltip_text: hyprland.active.client - .bind("class") - .as((v) => (v === "" ? "Desktop" : v)), - child: Widget.Box({ - spacing: 4, - vpack: "center", - children: [ - ClientIcon(), - Widget.Label({ - vpack: "center", - label: hyprland.active.client - .bind("title") - .as((t) => - t === "" - ? "Desktop" - : t.includes("Mozilla") - ? "Mozilla Firefox" - : t, - ), - visible: configs.theme.bar.position - .bind() - .as((p) => (p !== "left") & (p !== "right")), - }), - ], - }), - }); diff --git a/config/ags/widget/control_center/Brightness.js b/config/ags/widget/control_center/Brightness.js deleted file mode 100644 index 60507aba..00000000 --- a/config/ags/widget/control_center/Brightness.js +++ /dev/null @@ -1,18 +0,0 @@ -import brightness from "../../services/brightness.js"; - -export default () => - Widget.Box({ - spacing: 6, - vpack: "center", - class_name: "brightness-box", - children: [ - Widget.Icon({ icon: "display-brightness-symbolic", size: 18 }), - Widget.Slider({ - draw_value: false, - hexpand: true, - min: 0.1, - value: brightness.bind("screen"), - on_change: ({ value }) => (brightness.screen = value), - }), - ], - }); diff --git a/config/ags/widget/control_center/Media.js b/config/ags/widget/control_center/Media.js deleted file mode 100644 index 32543439..00000000 --- a/config/ags/widget/control_center/Media.js +++ /dev/null @@ -1,153 +0,0 @@ -const mpris = await Service.import("mpris"); -const players = mpris.bind("players"); - -const FALLBACK_ICON = "audio-x-generic-symbolic"; -const PLAY_ICON = "media-playback-start-symbolic"; -const PAUSE_ICON = "media-playback-pause-symbolic"; -const PREV_ICON = "media-skip-backward-symbolic"; -const NEXT_ICON = "media-skip-forward-symbolic"; - -function lengthStr(length) { - const min = Math.floor(length / 60); - const sec = Math.floor(length % 60); - const sec0 = sec < 10 ? "0" : ""; - return `${min}:${sec0}${sec}`; -} - -const Player = (player) => { - const img = Widget.Box({ - class_name: "img", - vpack: "start", - css: player.bind("cover_path").transform( - (p) => ` - background-image: url('${p}'); - `, - ), - }); - - const title = Widget.Label({ - class_name: "title", - wrap: true, - max_width_chars: 20, - truncate: "end", - hpack: "start", - label: player.bind("track_title"), - }); - - const artist = Widget.Label({ - class_name: "artist", - wrap: true, - hpack: "start", - label: player.bind("track_artists").transform((a) => a.join(", ")), - }); - - const positionSlider = Widget.Slider({ - class_name: "position", - draw_value: false, - on_change: ({ value }) => (player.position = value * player.length), - visible: player.bind("length").as((l) => l > 0), - hexpand: false, - setup: (self) => { - function update() { - const value = player.position / player.length; - self.value = value > 0 ? value : 0; - } - self.hook(player, update); - self.hook(player, update, "position"); - self.poll(1000, update); - }, - }); - - const positionLabel = Widget.Label({ - class_name: "position", - hpack: "start", - setup: (self) => { - const update = (_, time) => { - self.label = lengthStr(time || player.position); - self.visible = player.length > 0; - }; - - self.hook(player, update, "position"); - self.poll(1000, update); - }, - }); - - const lengthLabel = Widget.Label({ - class_name: "length", - hpack: "end", - visible: player.bind("length").transform((l) => l > 0), - label: player.bind("length").transform(lengthStr), - }); - - const icon = Widget.Icon({ - class_name: "icon", - hexpand: true, - hpack: "end", - vpack: "start", - tooltip_text: player.identity || "", - icon: player.bind("entry").transform((entry) => { - const name = `${entry}-symbolic`; - return Utils.lookUpIcon(name) ? name : FALLBACK_ICON; - }), - }); - - const playPause = Widget.Button({ - class_name: "play-pause", - on_clicked: () => player.playPause(), - visible: player.bind("can_play"), - child: Widget.Icon({ - icon: player.bind("play_back_status").transform((s) => { - switch (s) { - case "Playing": - return PAUSE_ICON; - case "Paused": - case "Stopped": - return PLAY_ICON; - } - }), - }), - }); - - const prev = Widget.Button({ - on_clicked: () => player.previous(), - visible: player.bind("can_go_prev"), - child: Widget.Icon(PREV_ICON), - }); - - const next = Widget.Button({ - on_clicked: () => player.next(), - visible: player.bind("can_go_next"), - child: Widget.Icon(NEXT_ICON), - }); - - return Widget.Box( - { class_names: ["player", "window-content"] }, - img, - Widget.Box( - { - vertical: true, - hexpand: true, - }, - Widget.Box([title, icon]), - artist, - Widget.Box({ vexpand: true }), - positionSlider, - Widget.CenterBox({ - start_widget: positionLabel, - center_widget: Widget.Box([prev, playPause, next]), - end_widget: lengthLabel, - }), - ), - ); -}; - -export function Media() { - return Widget.Box({ - vertical: true, - class_name: "media__container", - css: "min-height: 2px; min-width: 2px;", // small hack to make it visible - vexpand: false, - visible: players.as((p) => p.length > 0), - children: players.as((p) => p.map(Player)), - }); -} diff --git a/config/ags/widget/control_center/Notifications.js b/config/ags/widget/control_center/Notifications.js deleted file mode 100644 index 645bdf05..00000000 --- a/config/ags/widget/control_center/Notifications.js +++ /dev/null @@ -1,109 +0,0 @@ -import Notification from "../notifications/notifications.js"; - -const notifications = await Service.import("notifications"); -const notifs = notifications.bind("notifications"); - -const Animated = (n) => - Widget.Revealer({ - transition_duration: 200, - transition: "slide_left", - child: Notification(n), - setup: (self) => - Utils.timeout(200, () => { - if (!self.is_destroyed) self.reveal_child = true; - }), - }); - -const ClearButton = () => - Widget.Button({ - onClicked: () => notifications.clear(), - child: Widget.Icon({ - icon: notifications - .bind("notifications") - .as((n) => `user-trash-${n.length > 0 ? "full-" : ""}symbolic`), - }), - }); - -const Header = () => - Widget.Box({ - class_name: "header", - children: [ - Widget.Label({ label: "Notifications", xalign: 0, hexpand: true }), - ClearButton(), - ], - }); - -const NotificationList = () => { - const map = new Map(); - const box = Widget.Box({ - vertical: true, - children: notifications.notifications.map((n) => { - const w = Animated(n); - map.set(n.id, w); - return w; - }), - visible: notifs.as((n) => n.length > 0), - }); - - function remove(_, id) { - const n = map.get(id); - if (n) { - n.reveal_child = false; - Utils.timeout(200, () => { - n.destroy(); - map.delete(id); - }); - } - } - - return box.hook(notifications, remove, "closed").hook( - notifications, - (_, id) => { - if (id !== undefined) { - if (map.has(id)) remove(null, id); - - const n = notifications.getNotification(id); - - const w = Animated(n); - map.set(id, w); - box.children = [w, ...box.children]; - } - }, - "notified", - ); -}; - -const Placeholder = () => - Widget.Box({ - class_name: "placeholder", - vertical: true, - vpack: "center", - hpack: "center", - vexpand: true, - hexpand: true, - visible: notifs.as((n) => n.length === 0), - children: [ - Widget.Icon("notifications-disabled-symbolic"), - Widget.Label("Your inbox is empty"), - ], - }); - -export default ({ width = 250, height = 100 }) => - Widget.Box({ - class_name: "notifications__container", - css: `min-width: ${width}px; min-height: ${height}px;`, - vertical: true, - children: [ - Header(), - Widget.Scrollable({ - vexpand: true, - hscroll: "never", - class_name: "notification-scrollable", - child: Widget.Box({ - class_name: "notification-list vertical", - vertical: true, - children: [NotificationList(), Placeholder()], - }), - }), - ], - }); diff --git a/config/ags/widget/control_center/PanelButton.js b/config/ags/widget/control_center/PanelButton.js deleted file mode 100644 index 86d94cea..00000000 --- a/config/ags/widget/control_center/PanelButton.js +++ /dev/null @@ -1,25 +0,0 @@ -import PanelButton from "../PanelButton.js"; -import { WINDOW_NAME } from "./Window.js"; -const notifications = await Service.import("notifications"); - -const NotificationIcon = () => - Widget.Icon({ - class_name: "panel-control-center", - setup: (self) => { - self.hook(notifications, () => { - self.toggleClassName("empty", notifications.notifications.length == 0); - self.icon = notifications.dnd - ? "notifications-disabled-symbolic" - : "notifications-symbolic"; - }); - }, - }); - -export default () => - PanelButton({ - window: WINDOW_NAME, - child: NotificationIcon(), - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - }, - }); diff --git a/config/ags/widget/control_center/Window.js b/config/ags/widget/control_center/Window.js deleted file mode 100644 index abc047bb..00000000 --- a/config/ags/widget/control_center/Window.js +++ /dev/null @@ -1,50 +0,0 @@ -import PopupWindow from "../PopupWindow.js"; -import BrightnessSlider from "./Brightness.js"; -import QSButtonContainer from "./buttons/Container.js"; -import NotificationContainer from "./Notifications.js"; -import { Media } from "./Media.js"; -import { configs } from "../../vars.js"; -import { layoutPos } from "../../functions/utils.js"; - -export const WINDOW_NAME = "control-center__window"; -const { bar } = configs.theme; - -const Container = ({ width = 350 }) => - Widget.Box({ - vertical: true, - vexpand: true, - hexpand: false, - children: [ - Widget.Box({ - class_names: ["control-center__container", "window-content"], - css: `min-width: ${width}px;`, - hexpand: false, - vexpand: true, - vertical: true, - children: [ - BrightnessSlider(), - Widget.Separator(), - QSButtonContainer(), - Widget.Separator(), - NotificationContainer({}), - ], - }), - Media(), - ], - }); - -const ControlCenterWindow = () => - PopupWindow({ - name: WINDOW_NAME, - animation: "slide top", - layout: layoutPos(bar.position.value, "top-right"), - child: Container({}), - }); -export default function() { - App.addWindow(ControlCenterWindow()); - - bar.position.connect("changed", () => { - App.removeWindow(WINDOW_NAME); - App.addWindow(ControlCenterWindow()); - }); -} diff --git a/config/ags/widget/control_center/buttons/Container.js b/config/ags/widget/control_center/buttons/Container.js deleted file mode 100644 index c89b2276..00000000 --- a/config/ags/widget/control_center/buttons/Container.js +++ /dev/null @@ -1,28 +0,0 @@ -import Dnd from "./dnd.js"; -import Wallpaper from "./wallpaper.js"; -import DarkMode from "./dark_mode.js"; -import Screenshot from "./screenshot.js"; -import ScreenRecord from "./screen_record.js"; -import ColorPicker from "./color_picker.js"; -import MicAccess from "./mic_access.js"; -import PowerMenu from "./power_menu.js"; - -export default () => - Widget.Box({ - vertical: true, - spacing: 8, - class_name: "qs-buttons", - homogeneous: true, - children: [ - Widget.Box({ - spacing: 8, - homogeneous: true, - children: [Dnd(), Wallpaper(), DarkMode(), Screenshot()], - }), - Widget.Box({ - spacing: 8, - homogeneous: true, - children: [ScreenRecord(), ColorPicker(), MicAccess(), PowerMenu()], - }), - ], - }); diff --git a/config/ags/widget/control_center/buttons/color_picker.js b/config/ags/widget/control_center/buttons/color_picker.js deleted file mode 100644 index a2f69885..00000000 --- a/config/ags/widget/control_center/buttons/color_picker.js +++ /dev/null @@ -1,28 +0,0 @@ -import QsButton from "./qs_button.js"; -import { WINDOW_NAME } from "../Window.js"; - -const wlCopy = (color) => Utils.execAsync(["wl-copy", color]).catch(print); - -export default () => - QsButton({ - label: "Color Picker", - icon: "color-select-symbolic", - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - Utils.timeout(200, () => { - Utils.execAsync("hyprpicker") - .then((color) => { - if (!color) return; - - wlCopy(color); - Utils.notify({ - iconName: "color-select-symbolic", - summary: "Color Picker", - body: color, - timeout: 5000, - }); - }) - .catch(print); - }); - }, - }); diff --git a/config/ags/widget/control_center/buttons/dark_mode.js b/config/ags/widget/control_center/buttons/dark_mode.js deleted file mode 100644 index 9d243ae3..00000000 --- a/config/ags/widget/control_center/buttons/dark_mode.js +++ /dev/null @@ -1,16 +0,0 @@ -import QsButton from "./qs_button.js"; -import { configs } from "../../../vars.js"; - -export default () => - QsButton({ - icon: "night-symbolic", - label: "Dark Mode", - setup: (self) => { - self.hook(configs.theme.dark_mode, () => { - self.toggleClassName("active", configs.theme.dark_mode.value); - }); - }, - on_clicked: () => { - configs.theme.dark_mode.updateValue(!configs.theme.dark_mode.value); - }, - }); diff --git a/config/ags/widget/control_center/buttons/dnd.js b/config/ags/widget/control_center/buttons/dnd.js deleted file mode 100644 index a01c803a..00000000 --- a/config/ags/widget/control_center/buttons/dnd.js +++ /dev/null @@ -1,16 +0,0 @@ -import QsButton from "./qs_button.js"; -const notifications = await Service.import("notifications"); - -export default () => - QsButton({ - icon: notifications - .bind("dnd") - .as((dnd) => `notifications-${dnd ? "disabled-" : ""}symbolic`), - label: "DND", - setup: (self) => { - self.hook(notifications, () => { - self.toggleClassName("active", notifications.dnd); - }); - }, - on_clicked: () => (notifications.dnd = !notifications.dnd), - }); diff --git a/config/ags/widget/control_center/buttons/mic_access.js b/config/ags/widget/control_center/buttons/mic_access.js deleted file mode 100644 index 31aade5b..00000000 --- a/config/ags/widget/control_center/buttons/mic_access.js +++ /dev/null @@ -1,22 +0,0 @@ -const { microphone } = await Service.import("audio"); -import QsButton from "./qs_button.js"; - -const Icon = () => - microphone.is_muted || microphone.stream?.is_muted - ? "microphone-disabled-symbolic" - : "microphone-sensitivity-high-symbolic"; - -export default () => - QsButton({ - icon: Utils.watch(Icon(), microphone, Icon), - label: "Mic Access", - on_clicked: () => (microphone.is_muted = !microphone.is_muted), - setup: (self) => { - self.hook(microphone, () => { - self.toggleClassName( - "active", - !(microphone.is_muted || microphone.stream?.is_muted), - ); - }); - }, - }); diff --git a/config/ags/widget/control_center/buttons/power_menu.js b/config/ags/widget/control_center/buttons/power_menu.js deleted file mode 100644 index 001216d9..00000000 --- a/config/ags/widget/control_center/buttons/power_menu.js +++ /dev/null @@ -1,13 +0,0 @@ -import { WINDOW_NAME } from "../Window.js"; -import { WINDOW_NAME as POWERMENU_WINDOW } from "../../powermenu/PowerMenuWindow.js"; -import QsButton from "./qs_button.js"; - -export default () => - QsButton({ - icon: "system-shutdown-symbolic", - label: "Powermenu", - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - App.toggleWindow(POWERMENU_WINDOW); - }, - }); diff --git a/config/ags/widget/control_center/buttons/qs_button.js b/config/ags/widget/control_center/buttons/qs_button.js deleted file mode 100644 index 28c80560..00000000 --- a/config/ags/widget/control_center/buttons/qs_button.js +++ /dev/null @@ -1,23 +0,0 @@ -export default ({ icon, label, ...rest }) => - Widget.Button({ - class_name: "qs-button", - tooltip_text: label, - child: Widget.Box({ - vertical: true, - spacing: 4, - children: [ - Widget.Icon({ - icon: icon, - size: 18, - }), - Widget.Label({ - class_name: "label", - label: label, - maxWidthChars: 9, - wrap: true, - truncate: "end", - }), - ], - }), - ...rest, - }); diff --git a/config/ags/widget/control_center/buttons/screen_record.js b/config/ags/widget/control_center/buttons/screen_record.js deleted file mode 100644 index 3be118c1..00000000 --- a/config/ags/widget/control_center/buttons/screen_record.js +++ /dev/null @@ -1,22 +0,0 @@ -import QsButton from "./qs_button.js"; -import recorder from "../../../services/screen_record.js"; -import { WINDOW_NAME } from "../Window.js"; - -export default () => - QsButton({ - icon: "video-symbolic", - label: "Screen Record", - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - if (recorder.recording) { - recorder.stop(); - } else { - recorder.start(); - } - }, - setup: (self) => { - self.hook(recorder, () => { - self.toggleClassName("active", recorder.recording); - }); - }, - }); diff --git a/config/ags/widget/control_center/buttons/screenshot.js b/config/ags/widget/control_center/buttons/screenshot.js deleted file mode 100644 index 3530d109..00000000 --- a/config/ags/widget/control_center/buttons/screenshot.js +++ /dev/null @@ -1,44 +0,0 @@ -import QsButton from "./qs_button.js"; -import { WINDOW_NAME } from "../Window.js"; -import recorder from "../../../services/screen_record.js"; - -export default () => { - const menu = Widget.Menu({ - hpack: "start", - children: [ - Widget.MenuItem({ - hexpand: true, - on_activate: () => { - App.toggleWindow(WINDOW_NAME); - Utils.timeout(200, () => { - recorder.screenshot(true); - }); - }, - child: Widget.Label("Full", { - hexpand: true, - xalign: 0, - justification: "left", - }), - }), - Widget.MenuItem({ - hexpand: true, - on_activate: () => { - App.toggleWindow(WINDOW_NAME); - recorder.screenshot(); - }, - child: Widget.Label("Partial", { - hexpand: true, - xalign: 0, - justification: "left", - }), - }), - ], - }); - return QsButton({ - icon: "gnome-screenshot-symbolic", - label: "Screenshot", - on_primary_click: (_, event) => { - menu.popup_at_pointer(event); - }, - }); -}; diff --git a/config/ags/widget/control_center/buttons/wallpaper.js b/config/ags/widget/control_center/buttons/wallpaper.js deleted file mode 100644 index fed1878b..00000000 --- a/config/ags/widget/control_center/buttons/wallpaper.js +++ /dev/null @@ -1,13 +0,0 @@ -import { WINDOW_NAME } from "../Window.js"; -import { WINDOW_NAME as WALLPAPER_PICKER_WINDOW } from "../../wallpaper_picker/Window.js"; -import QsButton from "./qs_button.js"; - -export default () => - QsButton({ - icon: "emblem-photos-symbolic", - label: "Wallpaper", - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - App.toggleWindow(WALLPAPER_PICKER_WINDOW); - }, - }); diff --git a/config/ags/widget/datemenu/PanelButton.js b/config/ags/widget/datemenu/PanelButton.js deleted file mode 100644 index 1a30d24c..00000000 --- a/config/ags/widget/datemenu/PanelButton.js +++ /dev/null @@ -1,28 +0,0 @@ -import { isVertical } from "../../functions/utils.js"; -import { clock, configs } from "../../vars.js"; -import PanelButton from "../PanelButton.js"; -import { WINDOW_NAME } from "./Window.js"; - -export default () => - PanelButton({ - window: WINDOW_NAME, - // child: Widget.Label({ label: clock.bind().as((t) => t.format("%H:%M")) }), - child: Widget.Box({ - vertical: configs.theme.bar.position.bind().as(isVertical), - children: [ - Widget.Label({ label: clock.bind().as((t) => t.format("%I")) }), - Widget.Label({ - label: ":", - visible: configs.theme.bar.position - .bind() - .as((pos) => !isVertical(pos)), - }), - Widget.Label({ label: clock.bind().as((t) => t.format("%M")) }), - Widget.Label({ label: " " }), - Widget.Label({ label: clock.bind().as((t) => t.format("%p")) }), - ], - }), - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - }, - }); diff --git a/config/ags/widget/datemenu/Window.js b/config/ags/widget/datemenu/Window.js deleted file mode 100644 index 9a345eb9..00000000 --- a/config/ags/widget/datemenu/Window.js +++ /dev/null @@ -1,41 +0,0 @@ -import { layoutPos } from "../../functions/utils.js"; -import { clock, configs } from "../../vars.js"; -import PopupWindow from "../PopupWindow.js"; - -export const WINDOW_NAME = "datemenu__window"; - -const { bar } = configs.theme; - -const Container = () => - Widget.Box({ - vertical: true, - class_names: ["datemenu__container", "window-content"], - children: [ - Widget.Label({ - label: clock.bind().as((t) => t.format("%I:%M %p")), - class_name: "clock", - }), - Widget.Label({ - label: clock.bind().as((dt) => dt.format("%d/%m/%Y")), - class_name: "date", - }), - Widget.Calendar(), - ], - }); - -const DateMenuWindow = () => - PopupWindow({ - name: WINDOW_NAME, - layout: layoutPos(bar.position.value, "top-left"), - animation: "slide top", - child: Container(), - }); - -export default function() { - App.addWindow(DateMenuWindow()); - - bar.position.connect("changed", () => { - App.removeWindow(WINDOW_NAME); - App.addWindow(DateMenuWindow()); - }); -} diff --git a/config/ags/widget/hyprsplash/Window.js b/config/ags/widget/hyprsplash/Window.js deleted file mode 100644 index 866ebca0..00000000 --- a/config/ags/widget/hyprsplash/Window.js +++ /dev/null @@ -1,21 +0,0 @@ -import { isVertical } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; - -const Text = () => - Widget.Label({ - class_name: "splash-text", - label: Utils.exec("hyprctl splash"), - }); - -export default () => - Widget.Window({ - name: "hyprsplash__window", - layer: "bottom", - anchor: configs.theme.bar.position - .bind() - .as((v) => (v === "bottom" ? ["top"] : ["bottom"])), - margins: configs.theme.window.margin - .bind() - .as((v) => v.split(",").map(Number)), - child: Text(), - }); diff --git a/config/ags/widget/network/Bluetooth.js b/config/ags/widget/network/Bluetooth.js deleted file mode 100644 index e8063827..00000000 --- a/config/ags/widget/network/Bluetooth.js +++ /dev/null @@ -1,63 +0,0 @@ -import { ArrowToggleButton, Menu } from "../ToggleButton.js"; -const bluetooth = await Service.import("bluetooth"); - -export const BluetoothToggle = () => - ArrowToggleButton({ - name: "bluetooth", - icon: bluetooth - .bind("enabled") - .as((on) => `bluetooth-${on ? "active" : "disabled"}-symbolic`), - label: Utils.watch("Disabled", bluetooth, () => { - if (!bluetooth.enabled) return "Disabled"; - - if (bluetooth.connected_devices.length === 1) - return bluetooth.connected_devices[0].alias; - - return `${bluetooth.connected_devices.length} Connected`; - }), - connection: [bluetooth, () => bluetooth.enabled], - deactivate: () => (bluetooth.enabled = false), - activate: () => (bluetooth.enabled = true), - }); - -const DeviceItem = (device) => - Widget.Box({ - children: [ - Widget.Icon(device.icon_name + "-symbolic"), - Widget.Label(device.name), - Widget.Label({ - label: `${device.battery_percentage}%`, - visible: device.bind("battery_percentage").as((p) => p > 0), - }), - Widget.Box({ hexpand: true }), - Widget.Spinner({ - active: device.bind("connecting"), - visible: device.bind("connecting"), - }), - Widget.Switch({ - active: device.connected, - visible: device.bind("connecting").as((p) => !p), - setup: (self) => - self.on("notify::active", () => { - device.setConnection(self.active); - }), - }), - ], - }); - -export const BluetoothDevices = () => - Menu({ - name: "bluetooth", - icon: "bluetooth-disabled-symbolic", - title: "Bluetooth", - content: [ - Widget.Box({ - class_name: "bluetooth-devices", - hexpand: true, - vertical: true, - children: bluetooth - .bind("devices") - .as((ds) => ds.filter((d) => d.name).map(DeviceItem)), - }), - ], - }); diff --git a/config/ags/widget/network/PanelButton.js b/config/ags/widget/network/PanelButton.js deleted file mode 100644 index 88d8bc2c..00000000 --- a/config/ags/widget/network/PanelButton.js +++ /dev/null @@ -1,31 +0,0 @@ -const network = await Service.import("network"); -const bluetooth = await Service.import("bluetooth"); -import { isVertical } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; -import PanelButton from "../PanelButton.js"; -import { WINDOW_NAME } from "./Window.js"; - -const WifiIndicator = () => - Widget.Icon().hook(network, (self) => { - const icon = network[network.primary || "wifi"]?.icon_name; - self.icon = icon || ""; - self.visible = !!icon; - }); - -const BluetoothIndicator = () => - Widget.Icon("bluetooth-active-symbolic").hook(bluetooth, (self) => { - self.visible = bluetooth.enabled; - }); - -export default () => - PanelButton({ - window: WINDOW_NAME, - child: Widget.Box({ - spacing: 4, - vertical: configs.theme.bar.position.bind().as(isVertical), - children: [WifiIndicator(), BluetoothIndicator()], - }), - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - }, - }); diff --git a/config/ags/widget/network/Wifi.js b/config/ags/widget/network/Wifi.js deleted file mode 100644 index ccd6ec35..00000000 --- a/config/ags/widget/network/Wifi.js +++ /dev/null @@ -1,56 +0,0 @@ -import { ArrowToggleButton, Menu } from "../ToggleButton.js"; -const { wifi } = await Service.import("network"); -import { WINDOW_NAME } from "./Window.js"; - -export const NetworkToggle = () => - ArrowToggleButton({ - name: "network", - icon: wifi.bind("icon_name"), - label: wifi.bind("ssid").as((ssid) => ssid || "Not Connected"), - connection: [wifi, () => wifi.enabled], - deactivate: () => (wifi.enabled = false), - activate: () => { - wifi.enabled = true; - wifi.scan(); - }, - }); - -export const WifiSelection = () => - Menu({ - name: "network", - parentWindowName: WINDOW_NAME, - icon: wifi.bind("icon_name"), - title: "Wifi Selection", - content: [ - Widget.Box({ - vertical: true, - setup: (self) => - self.hook( - wifi, - () => - (self.children = wifi.access_points.map((ap) => - Widget.Button({ - on_clicked: () => { - Utils.execAsync(`nmcli device wifi connect ${ap.bssid}`); - }, - child: Widget.Box({ - children: [ - Widget.Icon(ap.iconName), - Widget.Label(ap.ssid || ""), - Widget.Icon({ - icon: "object-select-symbolic", - hexpand: true, - hpack: "end", - setup: (self) => - Utils.idle(() => { - if (!self.is_destroyed) self.visible = ap.active; - }), - }), - ], - }), - }), - )), - ), - }), - ], - }); diff --git a/config/ags/widget/network/Window.js b/config/ags/widget/network/Window.js deleted file mode 100644 index d0f3c8ae..00000000 --- a/config/ags/widget/network/Window.js +++ /dev/null @@ -1,35 +0,0 @@ -import PopupWindow from "../PopupWindow.js"; -import { WifiSelection, NetworkToggle } from "./Wifi.js"; -import { BluetoothDevices, BluetoothToggle } from "./Bluetooth.js"; -import { Row } from "../ToggleButton.js"; -import { configs } from "../../vars.js"; -import { layoutPos } from "../../functions/utils.js"; -export const WINDOW_NAME = "network__window"; -const { bar } = configs.theme; - -const Container = () => - Widget.Box({ - class_names: ["network-info__container", "window-content"], - hexpand: false, - vertical: true, - children: [ - Row([NetworkToggle, BluetoothToggle], [WifiSelection, BluetoothDevices]), - ], - }); - -const NetworkWindow = () => - PopupWindow({ - name: WINDOW_NAME, - layout: layoutPos(bar.position.value, "top-right"), - animation: "slide top", - child: Container(), - }); - -export default function() { - App.addWindow(NetworkWindow()); - - bar.position.connect("changed", () => { - App.removeWindow(WINDOW_NAME); - App.addWindow(NetworkWindow()); - }); -} diff --git a/config/ags/widget/network_speed/PanelButton.js b/config/ags/widget/network_speed/PanelButton.js deleted file mode 100644 index 97f5a120..00000000 --- a/config/ags/widget/network_speed/PanelButton.js +++ /dev/null @@ -1,37 +0,0 @@ -import { isVertical } from "../../functions/utils.js"; -import networkspeed from "../../services/network_speed.js"; -import { configs } from "../../vars.js"; -import PanelButton from "../PanelButton.js"; - -// networkspeed.interval = 3000; - -const NetworkSpeedLabel = (inMB = true) => - Widget.Label({ class_name: "label" }) - .hook(networkspeed, (self) => { - let downloadSpeed = networkspeed.download_speed; - let uploadSpeed = networkspeed.upload_speed; - let speed = downloadSpeed >= uploadSpeed ? downloadSpeed : uploadSpeed; - if (inMB) { - speed = (speed / 1000).toFixed(2); - } - const unit = downloadSpeed >= uploadSpeed ? "" : ""; - self.label = `${speed} ${unit}`; - }) - .hook(configs.theme.bar.position, (self) => { - self.toggleClassName( - "vert", - isVertical(configs.theme.bar.position.value), - ); - }); - -export default () => - PanelButton({ - class_name: "network-speed", - child: Widget.Box({ - vertical: true, - children: [ - NetworkSpeedLabel(), - Widget.Label({ class_name: "unit", label: "MB/s" }), - ], - }), - }); diff --git a/config/ags/widget/notifications/PopupWindow.js b/config/ags/widget/notifications/PopupWindow.js deleted file mode 100644 index 43510613..00000000 --- a/config/ags/widget/notifications/PopupWindow.js +++ /dev/null @@ -1,100 +0,0 @@ -import Notification from "./notifications.js"; -// import { configs } from "../../vars.js"; - -const notifications = await Service.import("notifications"); -const transition = 900; -const { timeout, idle } = Utils; - -function Animated(id) { - const n = notifications.getNotification(id); - const widget = Notification(n); - - const inner = Widget.Revealer({ - transition: "slide_left", - transition_duration: transition, - child: widget, - }); - - const outer = Widget.Revealer({ - transition: "slide_down", - transition_duration: transition, - child: inner, - }); - - const box = Widget.Box({ - hpack: "end", - child: outer, - }); - - idle(() => { - outer.reveal_child = true; - timeout(transition, () => { - inner.reveal_child = true; - }); - }); - - return Object.assign(box, { - dismiss() { - inner.reveal_child = false; - timeout(transition, () => { - outer.reveal_child = false; - timeout(transition, () => { - box.destroy(); - }); - }); - }, - }); -} - -function PopupList() { - const map = new Map(); - const box = Widget.Box({ - hpack: "end", - vertical: true, - spacing: 8, - css: `min-width: 350px;`, - }); - - function remove(_, id) { - map.get(id)?.dismiss(); - map.delete(id); - } - - return box - .hook( - notifications, - (_, id) => { - if (id !== undefined) { - if (map.has(id)) remove(null, id); - - if (notifications.dnd) return; - - const w = Animated(id); - map.set(id, w); - box.children = [w, ...box.children]; - } - }, - "notified", - ) - .hook(notifications, remove, "dismissed") - .hook(notifications, remove, "closed"); -} - -export default (monitor = "") => { - const win = Widget.Window({ - monitor, - name: `notifications${monitor}`, - anchor: ["bottom", "right"], - class_name: "notifications", - child: Widget.Box({ - css: "padding: 0.1px;", - child: PopupList(), - }), - }); - - Object.assign(win, { - //disable? - animation: "0", - }); - return win; -}; diff --git a/config/ags/widget/notifications/notifications.js b/config/ags/widget/notifications/notifications.js deleted file mode 100644 index b0c5c5e4..00000000 --- a/config/ags/widget/notifications/notifications.js +++ /dev/null @@ -1,139 +0,0 @@ -import GLib from "gi://GLib"; - -const time = (time, format = "%I:%M %p") => - GLib.DateTime.new_from_unix_local(time).format(format); - -const NotificationIcon = ({ app_entry, app_icon, image }) => { - if (image) { - return Widget.Box({ - vpack: "start", - hexpand: false, - class_name: "icon img", - css: ` - background-image: url("${image}"); - background-size: cover; - background-repeat: no-repeat; - background-position: center; - min-width: 60px; - min-height: 60px; - `, - }); - } - - let icon = "dialog-information-symbolic"; - - if (Utils.lookUpIcon(app_icon)) icon = app_icon; - - if (Utils.lookUpIcon(app_entry || "")) icon = app_entry || ""; - - return Widget.Box({ - vpack: "start", - hexpand: false, - class_name: "icon", - css: ` - min-width: 60px; - min-height: 60px; - `, - child: Widget.Icon({ - icon, - size: 48, - hpack: "center", - hexpand: true, - vpack: "center", - vexpand: true, - }), - }); -}; - -export default (notification) => { - const content = Widget.Box({ - class_name: "content", - children: [ - NotificationIcon(notification), - Widget.Box({ - hexpand: true, - vertical: true, - children: [ - Widget.Box({ - children: [ - Widget.Label({ - class_name: "title", - xalign: 0, - justification: "left", - hexpand: true, - max_width_chars: 16, - truncate: "end", - wrap: true, - label: notification.summary.trim(), - use_markup: true, - }), - Widget.Label({ - class_name: "time", - vpack: "start", - label: time(notification.time), - }), - Widget.Button({ - class_name: "close-button", - vpack: "start", - child: Widget.Icon("window-close-symbolic"), - on_clicked: notification.close, - }), - ], - }), - Widget.Label({ - class_name: "description", - hexpand: true, - use_markup: true, - xalign: 0, - justification: "left", - label: notification.body.trim(), - max_width_chars: 24, - wrap: true, - }), - ], - }), - ], - }); - - const actionsbox = - notification.actions.length > 0 - ? Widget.Revealer({ - transition: "slide_down", - child: Widget.EventBox({ - child: Widget.Box({ - class_name: "actions horizontal", - children: notification.actions.map((action) => - Widget.Button({ - class_name: "action-button", - on_clicked: () => notification.invoke(action.id), - hexpand: true, - child: Widget.Label(action.label), - }), - ), - }), - }), - }) - : null; - - const eventbox = Widget.EventBox({ - vexpand: false, - on_primary_click: notification.dismiss, - on_hover() { - if (actionsbox) actionsbox.reveal_child = true; - }, - on_hover_lost() { - if (actionsbox) actionsbox.reveal_child = true; - - notification.dismiss(); - }, - child: Widget.Box({ - vertical: true, - children: actionsbox ? [content, actionsbox] : [content], - }), - }); - - return Widget.Box({ - class_name: `notification ${notification.urgency}`, - child: eventbox, - }); -}; diff --git a/config/ags/widget/osd/Progress.js b/config/ags/widget/osd/Progress.js deleted file mode 100644 index 5e4e5f00..00000000 --- a/config/ags/widget/osd/Progress.js +++ /dev/null @@ -1,63 +0,0 @@ -import GLib from "gi://GLib?version=2.0"; - -function range(length, start = 1) { - return Array.from({ length }, (_, i) => i + start); -} - -export default ({ height = 18, width = 180, vertical = false, child }) => { - const fill = Widget.Box({ - class_name: "fill", - hexpand: vertical, - vexpand: !vertical, - hpack: vertical ? "fill" : "start", - vpack: vertical ? "end" : "fill", - child, - }); - - const container = Widget.Box({ - class_name: "progress", - child: fill, - css: ` - min-width: ${width}px; - min-height: ${height}px; - `, - }); - - let fill_size = 0; - let animations = []; - - return Object.assign(container, { - setValue(value) { - if (value < 0) return; - - if (animations.length > 0) { - for (const id of animations) GLib.source_remove(id); - - animations = []; - } - - const axis = vertical ? "height" : "width"; - const axisv = vertical ? height : width; - const min = vertical ? width : height; - const preferred = (axisv - min) * value + min; - - if (!fill_size) { - fill_size = preferred; - fill.css = `min-${axis}: ${preferred}px;`; - return; - } - - const frames = 100 / 10; - const goal = preferred - fill_size; - const step = goal / frames; - - animations = range(frames, 0).map((i) => - Utils.timeout(5 * i, () => { - fill_size += step; - fill.css = `min-${axis}: ${fill_size}px`; - animations.shift(); - }), - ); - }, - }); -}; diff --git a/config/ags/widget/osd/ProgressOsd.js b/config/ags/widget/osd/ProgressOsd.js deleted file mode 100644 index 10a2506e..00000000 --- a/config/ags/widget/osd/ProgressOsd.js +++ /dev/null @@ -1,83 +0,0 @@ -import brightness from "../../services/brightness.js"; -import { icon } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; -import Progress from "./Progress.js"; -const WINDOW_NAME = "osd__window"; -const DELAY = 3000; - -const audio = await Service.import("audio"); - -const Container = (vertical) => { - const indicator = Widget.Icon({ - class_name: "icon", - size: 40, - vpack: "end", - hpack: "start", - }); - - const progress = Progress({ - vertical, - width: vertical ? 40 : 200, - height: vertical ? 260 : 40, - child: indicator, - }); - - let count = 0; - function show(value, icon) { - indicator.icon = icon; - progress.setValue(value); - App.openWindow(WINDOW_NAME); - count++; - Utils.timeout(DELAY, () => { - count--; - - if (count === 0) App.closeWindow(WINDOW_NAME); - }); - } - - const box = Widget.Box({ - class_name: "osd progress", - children: [progress], - setup: (self) => { - self.hook(configs.osd.progress.brightness, () => { - self.hook( - brightness, - () => { - if (configs.osd.progress.brightness.value) - show(brightness.screen, "display-brightness-symbolic"); - }, - "notify::screen", - ); - }); - - self.hook(configs.osd.progress.volume, () => { - self.hook( - audio.speaker, - () => { - if (configs.osd.progress.volume.value) - show( - audio.speaker.volume, - icon(audio.speaker.icon_name || "", "audio-x-generic-symbolic"), - ); - }, - "notify::volume", - ); - }); - }, - }); - - return box; -}; - -export default () => { - const win = Widget.Window({ - name: WINDOW_NAME, - click_through: true, - anchor: configs.osd.progress.position.bind().as((v) => v.split(" ")), - visible: false, - layer: "overlay", - child: configs.osd.progress.vertical.bind().as(Container), - }); - - return win; -}; diff --git a/config/ags/widget/osd/RegularOsd.js b/config/ags/widget/osd/RegularOsd.js deleted file mode 100644 index 56f91386..00000000 --- a/config/ags/widget/osd/RegularOsd.js +++ /dev/null @@ -1,99 +0,0 @@ -import { capsLockState, configs } from "../../vars.js"; - -const { microphone } = await Service.import("audio"); -const WINDOW_NAME = "osd__capslock"; -const DELAY = 3000; - -const Container = () => { - const indicator = Widget.Icon({ - class_name: "icon", - size: 60, - vpack: "start", - }); - - const label = Widget.Label({}); - - let count = 0; - function show(label_text, icon) { - indicator.icon = icon; - label.label = label_text; - App.openWindow(WINDOW_NAME); - count++; - Utils.timeout(DELAY, () => { - count--; - - if (count === 0) App.closeWindow(WINDOW_NAME); - }); - } - - const box = Widget.Box({ - class_name: "osd regular", - vertical: configs.osd.regular.vertical.bind(), - children: [indicator, label], - spacing: 6, - setup: (self) => { - self.hook(configs.osd.regular.capslock, () => { - self.hook(capsLockState, () => { - const value = capsLockState.value; - const icon = `capslock-${value === "1" ? "enabled" : "disabled"}-symbolic`; - if (configs.osd.regular.capslock.value) - show(`Capslock ${value === "1" ? "On" : "Off"}`, icon); - }); - }); - - self.hook(configs.osd.regular.mic, () => { - if (configs.osd.regular.mic.value) { - self.hook(microphone, () => { - const value = microphone.is_muted; - const icon = `microphone-${value ? "disabled" : "sensitivity-high"}-symbolic`; - - if (configs.osd.regular.mic.value) - show(`Mic ${!value ? "On" : "Off"}`, icon); - }); - } - }); - }, - }); - - // box.hook(capsLockState, () => { - // const value = capsLockState.value; - // const icon = `capslock-${value === "1" ? "enabled" : "disabled"}-symbolic`; - // if (configs.osd.regular.capslock.value) - // show(`Capslock ${value === "1" ? "On" : "Off"}`, icon); - // }); - // - // box.hook(microphone, () => { - // const value = microphone.is_muted; - // const icon = `microphone-${value ? "disabled" : "sensitivity-high"}-symbolic`; - // - // if (configs.osd.regular.mic.value) - // show(`Capslock ${value === "1" ? "On" : "Off"}`, icon); - // }); - - return box; -}; - -export default () => { - const win = Widget.Window({ - name: WINDOW_NAME, - click_through: true, - anchor: configs.osd.regular.position.bind().as((v) => v.split(" ")), - visible: false, - layer: "overlay", - child: Container(), - // setup: (self) => { - // self.child = Container(); - // self.hook(configs.osd.regular.capslock, () => { - // self.child = Container(); - // }); - // - // self.hook(microphone, () => { - // self.child = Container(); - // }); - // }, - }); - // Object.assign(win, { - // animation: "popin 100%", - // }); - return win; -}; diff --git a/config/ags/widget/powermenu/PowerMenuWindow.js b/config/ags/widget/powermenu/PowerMenuWindow.js deleted file mode 100644 index 3cc18c12..00000000 --- a/config/ags/widget/powermenu/PowerMenuWindow.js +++ /dev/null @@ -1,48 +0,0 @@ -import powermenu from "../../services/powermenu.js"; -import PopupWindow from "../PopupWindow.js"; - -export const WINDOW_NAME = "powermenu__window"; - -const icons = { - lock: "system-lock-screen-symbolic", - sleep: "weather-clear-night-symbolic", - reboot: "system-reboot-symbolic", - logout: "system-log-out-symbolic", - shutdown: "system-shutdown-symbolic", -}; - -const SysButton = (action, label) => - Widget.Button({ - on_clicked: () => powermenu.action(action), - child: Widget.Box({ - vertical: true, - class_name: "system-button", - children: [ - Widget.Icon(icons[action]), - Widget.Label({ - label, - }), - ], - }), - }); - -const Container = () => - Widget.Box({ - class_names: ["powermenu__container", "window-content"], - spacing: 6, - homogeneous: true, - children: [ - SysButton("lock", "Lock"), - SysButton("sleep", "Sleep"), - SysButton("logout", "Log Out"), - SysButton("reboot", "Reboot"), - SysButton("shutdown", "Shutdown"), - ], - }); - -export default () => - PopupWindow({ - name: WINDOW_NAME, - exclusivity: "ignore", - child: Container(), - }); diff --git a/config/ags/widget/powermenu/VerificationWindow.js b/config/ags/widget/powermenu/VerificationWindow.js deleted file mode 100644 index d56533d3..00000000 --- a/config/ags/widget/powermenu/VerificationWindow.js +++ /dev/null @@ -1,54 +0,0 @@ -import powermenu from "../../services/powermenu.js"; -import PopupWindow from "../PopupWindow.js"; - -const WINDOW_NAME = "verification__window"; - -const Container = () => - Widget.Box({ - class_names: ["verification__container", "window-content"], - vertical: true, - children: [ - Widget.Box({ - class_name: "text-box", - vertical: true, - children: [ - Widget.Label({ - class_name: "title", - label: powermenu.bind("title"), - }), - Widget.Label({ - class_name: "desc", - label: "Are you sure?", - }), - ], - }), - Widget.Box({ - class_name: "buttons", - vexpand: true, - vpack: "end", - homogeneous: true, - spacing: 6, - children: [ - Widget.Button({ - child: Widget.Label("No"), - on_clicked: () => App.toggleWindow(WINDOW_NAME), - setup: (self) => - self.hook(App, (_, name, visible) => { - if (name === WINDOW_NAME && visible) self.grab_focus(); - }), - }), - Widget.Button({ - child: Widget.Label("Yes"), - on_clicked: () => Utils.exec(powermenu.cmd), - }), - ], - }), - ], - }); - -export default () => - PopupWindow({ - name: WINDOW_NAME, - exclusivity: "ignore", - child: Container(), - }); diff --git a/config/ags/widget/screen_record/PanelButton.js b/config/ags/widget/screen_record/PanelButton.js deleted file mode 100644 index 47d43ef6..00000000 --- a/config/ags/widget/screen_record/PanelButton.js +++ /dev/null @@ -1,32 +0,0 @@ -import PanelButton from "../PanelButton.js"; -import recorder from "../../services/screen_record.js"; -import { configs } from "../../vars.js"; -import { isVertical } from "../../functions/utils.js"; - -export default () => - PanelButton({ - on_clicked: () => recorder.stop(), - visible: recorder.bind("recording"), - child: Widget.Box({ - vertical: configs.theme.bar.position.bind().as(isVertical), - children: [ - Widget.Icon("media-record-symbolic"), - Widget.Label({ - class_name: "timer", - label: recorder.bind("timer").as((time) => { - const sec = time % 60; - const min = Math.floor(time / 60); - return `${min}:${sec < 10 ? "0" + sec : sec}`; - }), - setup: (self) => { - self.hook(configs.theme.bar.position, () => { - self.toggleClassName( - "vert", - isVertical(configs.theme.bar.position.value), - ); - }); - }, - }), - ], - }), - }); diff --git a/config/ags/widget/system_monitor/Window.js b/config/ags/widget/system_monitor/Window.js deleted file mode 100644 index b7054452..00000000 --- a/config/ags/widget/system_monitor/Window.js +++ /dev/null @@ -1,126 +0,0 @@ -import { cpu, ram, configs, clock } from "../../vars.js"; - -const CpuProgress = () => - Widget.Box({ - class_name: "cpu-box", - spacing: 4, - children: [ - Widget.CircularProgress({ - class_name: "progress", - value: cpu.bind(), - child: Widget.Icon({ - icon: "applications-electronics-symbolic", - hpack: "center", - }), - }), - Widget.Box({ - vertical: true, - vpack: "center", - children: [ - Widget.Label({ - class_name: "label", - label: "CPU:", - hpack: "start", - }), - Widget.Label({ - class_name: "value", - label: cpu.bind().as((v) => `${(v * 100).toFixed(1)}%`), - }), - ], - }), - ], - }); - -const RamProgress = () => - Widget.Box({ - spacing: 4, - children: [ - Widget.CircularProgress({ - class_name: "progress", - value: ram.bind(), - child: Widget.Icon({ icon: "nvidia-ram-symbolic", hpack: "center" }), - }), - Widget.Box({ - vertical: true, - vpack: "center", - children: [ - Widget.Label({ - class_name: "label", - label: "RAM:", - hpack: "start", - }), - Widget.Label({ - class_name: "value", - label: ram.bind().as((v) => `${(v * 100).toFixed(1)}%`), - }), - ], - }), - ], - }); - -const CpuAndRam = () => - Widget.Box({ - hpack: "center", - children: [CpuProgress(), RamProgress()], - }); - -const Hari = () => - Widget.Label({ - class_name: "day", - hpack: "start", - label: clock.bind().as((t) => t.format("%A").toUpperCase()), - }); - -const Tanggal = () => - Widget.Box({ - vpack: "end", - hpack: "end", - children: [ - Widget.Label({ - class_name: "day-number", - label: clock.bind().as((t) => t.format("%d") + " "), - vpack: "end", - }), - Widget.Label({ - class_name: "month", - vpack: "end", - label: clock.bind().as((t) => t.format("%B")), - }), - ], - }); - -const Date = () => - Widget.Overlay({ - child: Hari(), - overlays: [Tanggal()], - }); - -const DayDots = () => - Widget.Box({ - class_name: "day-dots", - spacing: 8, - hpack: "center", - children: clock.bind().as((t) => { - const format = Number(t.format("%u")) % 7; // Adjust for Sunday being 0 - const dots = [...Array(7).keys()].map((day) => - day <= format ? Widget.Box({ class_name: "fill" }) : Widget.Box({ class_name: "empty" }) - ); - return dots; - }), - }); - -const Container = () => - Widget.Box({ - class_names: ["system-monitor__container", "window-content"], - vertical: true, - spacing: 8, - children: [Date(), DayDots(), Widget.Separator(), CpuAndRam()], - }); - -export default () => - Widget.Window({ - name: "system-monitor__window", - anchor: configs.system_monitor.position.bind().as((v) => v.split(" ")), - layer: "bottom", - child: Container(), - }); diff --git a/config/ags/widget/tray/tray.js b/config/ags/widget/tray/tray.js deleted file mode 100644 index 92a5fcf6..00000000 --- a/config/ags/widget/tray/tray.js +++ /dev/null @@ -1,16 +0,0 @@ -const systemtray = await Service.import("systemtray") - -export default () => Widget.Box({ - class_name: "tray", - children: systemtray.bind("items").as( - items => items.map(item => Widget.Button({ - child: Widget.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"), - })) - ), - setup: self => self.hook(systemtray, self => { - self.visible = self.children.length > 0 - }) -}) diff --git a/config/ags/widget/wallpaper_picker/Window.js b/config/ags/widget/wallpaper_picker/Window.js deleted file mode 100644 index cd50c55e..00000000 --- a/config/ags/widget/wallpaper_picker/Window.js +++ /dev/null @@ -1,187 +0,0 @@ -import PopupWindow from "../PopupWindow.js"; -import FileChooserDialog from "../FileChooserDialog.js"; -import { configs } from "../../vars.js"; - -export const WINDOW_NAME = "wallpaper-picker__window"; - -function updateWallpaper(path) { - configs.wallpaper.current.updateValue(getFilename(path)); -} - -function getWallpaperList(path) { - const imageFormats = [".jpeg", ".jpg", ".webp", ".png"]; - return Utils.exec(`ls ${path} -1`) - .split("\n") - .filter((str) => { - return imageFormats.some((fmt) => str.endsWith(fmt)); - }); -} - -function getFilename(str) { - return str.split("\\").pop().split("/").pop(); -} - -const WallItem = (folder, wall) => - Widget.Button({ - class_name: "item", - on_clicked: () => { - updateWallpaper(`${folder}/${wall}`); - }, - attribute: { wall: `${folder}/${wall}` }, - child: Widget.Box({ - children: [ - Widget.Label({ - class_name: "title", - label: wall, - xalign: 0, - hexpand: true, - vpack: "center", - truncate: "end", - }), - Widget.Label({ - // icon: "object-select-symbolic", - label: "󰄬", - class_name: "checkmark", - setup: (self) => { - self.hook(configs.wallpaper.current, (icon) => { - icon.visible = configs.wallpaper.current.value == wall; - }); - }, - }), - ], - }), - }); - -const WallpaperPicker = ({ width = 500, spacing = 12 }) => { - const list = Widget.Box({ - vertical: true, - spacing, - hexpand: true, - }).hook(configs.wallpaper.folder, (self) => { - const path = configs.wallpaper.folder.value; - self.vpack = "start"; - self.children = getWallpaperList(path).map((item) => WallItem(path, item)); - - if (self.children.length == 0) { - self.vpack = "center"; - self.children = [ - Widget.Label({ - hpack: "center", - label: "There's nothing here.", - css: "font-size: 14px; font-weight: 600;", - }), - ]; - } - }); - - const entry = Widget.Box({ - class_name: "entry-box", - children: [ - Widget.Icon("search-symbolic"), - Widget.Entry({ - hexpand: true, - on_accept: () => { - const results = list.children.filter((item) => item.visible); - if (results[0]) { - updateWallpaper(results[0].attribute.wall); - } - }, - on_change: ({ text }) => - list.children.forEach((item) => { - item.visible = getFilename(item.attribute.wall).match( - text.toLowerCase() ?? "", - ); - }), - setup: (self) => - self.hook(App, (_, windowName, visible) => { - if (windowName !== WINDOW_NAME) return; - - if (visible) { - self.text = ""; - self.grab_focus(); - } - }), - }), - ], - }); - - return Widget.Box({ - class_names: ["wallpaper-picker__container", "window-content"], - vertical: true, - vexpand: true, - children: [ - Widget.Box({ - spacing: 8, - children: [ - entry, - Widget.Button({ - class_name: "folder-button", - on_clicked: () => { - App.toggleWindow(WINDOW_NAME); - App.toggleWindow("wall-filechooser"); - return false; - }, - child: Widget.Icon({ icon: "folder-open-symbolic" }), - }), - ], - }), - Widget.Label({ - class_name: "path", - css: `margin-bottom: ${spacing}px`, - label: configs.wallpaper.folder.bind().as((p) => `Path: ${p}`), - truncate: "end", - max_width_chars: 40, - hpack: "start", - }), - Widget.Scrollable({ - hscroll: "never", - css: `min-width: ${width}px;`, - vexpand: true, - child: Widget.Box({ vexpand: true, children: [list] }), - }), - ], - }); -}; - -export const WallpaperPickerWindow = () => - PopupWindow({ - name: WINDOW_NAME, - layout: "right", - animation: "slide right", - child: WallpaperPicker({ - width: 300, - spacing: 5, - }), - }); - -export const FolderChooserWindow = () => - FileChooserDialog({ - name: "wall-filechooser", - action: 2, - "use-header-bar": false, - "create-folders": false, - setup(win) { - win.on("delete-event", () => { - win.hide(); - App.toggleWindow(WINDOW_NAME); - return true; - }); - - win.add_button("Cancel", 2); - win.add_button("Choose Folder", 1); - - win.on("response", (_, id) => { - if (id == 2) { - win.hide(); - App.toggleWindow(WINDOW_NAME); - } else { - const choosen = win.get_file(); - if (choosen != null) { - configs.wallpaper.folder.updateValue(choosen.get_path()); - win.hide(); - App.toggleWindow(WINDOW_NAME); - } - } - }); - }, - }); diff --git a/config/ags/widget/workspaces/PanelButton.js b/config/ags/widget/workspaces/PanelButton.js deleted file mode 100644 index 7368ffb0..00000000 --- a/config/ags/widget/workspaces/PanelButton.js +++ /dev/null @@ -1,102 +0,0 @@ -import { isVertical } from "../../functions/utils.js"; -import { configs } from "../../vars.js"; - -const hyprland = await Service.import("hyprland"); -const dispatch = (ws) => hyprland.messageAsync(`dispatch workspace ${ws}`); - -const WorkspaceButton = (ws) => - Widget.Button({ - class_name: "workspace-button", - child: Widget.Label({ - label: getNerdFontIcon(ws.id), // Use a function to get the icon - class_name: "workspace-icon", - }), - vpack: "center", - hpack: "center", - onClicked: () => dispatch(ws.id), - setup: (self) => { - self.hook(hyprland, () => { - self.toggleClassName("active", hyprland.active.workspace.id == ws.id); - self.toggleClassName( - "occupied", - hyprland.getWorkspace(ws.id)?.windows > 0, - ); - }); - }, - }); - -function getNerdFontIcon(workspaceId) { - // Return different icons based on workspaceId - const icons = { - 1: '  ', - 2: '  ', - 3: '  ', - 4: '  ', - 5: '  ', - 6: '  ', - 7: '  ', - 8: '  ', - 9: ' 󰚌 ', - }; - return icons[workspaceId] || '  '; // Default icon if workspaceId not found -} - -async function fetchWorkspacesFromServer() { - // Fetch workspaces from a server or other source - // Example return value - return await fetch('/api/workspaces').then(response => response.json()); -} - -function createInitialWorkspaces() { - // Create an initial set of workspaces - return [ - { id: 1, name: "Workspace 1" }, - { id: 2, name: "Workspace 2" }, - { id: 3, name: "Workspace 3" }, - { id: 4, name: "Workspace 4" }, - // Add more initial workspaces as needed - ]; -} - -export default () => { - const wsBox = Widget.Box({ - class_names: ["workspace__container"], - spacing: 4, - hexpand: false, - vexpand: false, - vertical: configs.theme.bar.position.bind().as(isVertical), - setup: async (self) => { - // Ensure workspaces array exists and is properly initialized - if (!hyprland.workspaces || !Array.isArray(hyprland.workspaces)) { - hyprland.workspaces = []; // Initialize the workspaces array if it doesn't exist - } - - // Fetch or create workspaces if the array is empty - if (hyprland.workspaces.length === 0) { - try { - hyprland.workspaces = await fetchWorkspacesFromServer(); - } catch (error) { - console.error("Failed to fetch workspaces from server:", error); - hyprland.workspaces = createInitialWorkspaces(); - } - } - - // Update the workspace buttons whenever there's a change in workspaces - self.hook( - hyprland, - () => { - // Clear existing buttons - self.children = []; - - // Map existing workspaces to buttons - self.children = hyprland.workspaces.map(WorkspaceButton); - }, - "notify::workspaces", - ); - }, - }); - - return Widget.EventBox({ - child: wsBox, - }); -}; diff --git a/config/ags/windows.js b/config/ags/windows.js deleted file mode 100644 index b9eecedf..00000000 --- a/config/ags/windows.js +++ /dev/null @@ -1,44 +0,0 @@ -import { - FolderChooserWindow, - WallpaperPickerWindow, -} from "./widget/wallpaper_picker/Window.js"; -import AppLauncherWindow from "./widget/applauncher/Window.js"; -import HyprsplashWindow from "./widget/hyprsplash/Window.js"; -import NotificationPopupWindow from "./widget/notifications/PopupWindow.js"; -import VerificationWindow from "./widget/powermenu/VerificationWindow.js"; -import PowerMenuWindow from "./widget/powermenu/PowerMenuWindow.js"; -import SystemMonitorWindow from "./widget/system_monitor/Window.js"; -import ProgressOsd from "./widget/osd/ProgressOsd.js"; -import RegularOsd from "./widget/osd/RegularOsd.js"; -import SetupDatemenuWindow from "./widget/datemenu/Window.js"; -import SetupAudioWindow from "./widget/audio/Window.js"; -import SetupNetworkWindow from "./widget/network/Window.js"; -import SetupBatteryWindow from "./widget/battery/Window.js"; -import SetupControlCenterWindow from "./widget/control_center/Window.js"; -import SetupBarWindow from "./widget/bar/Window.js"; -import Tray from "./widget/tray/tray.js"; - -App.addIcons(`${App.configDir}/assets`); - -export function setupWindows() { - SetupDatemenuWindow(); - SetupAudioWindow(); - SetupNetworkWindow(); - SetupBatteryWindow(); - SetupControlCenterWindow(); - SetupBarWindow(); - Tray(); -} - -export default [ - WallpaperPickerWindow(), - FolderChooserWindow(), - AppLauncherWindow(), - NotificationPopupWindow(), - PowerMenuWindow(), - VerificationWindow(), - //HyprsplashWindow(), - SystemMonitorWindow(), - ProgressOsd(), - RegularOsd(), -];