From ce7da7ab269471e3d0c9fa56d9fdebeca2789e13 Mon Sep 17 00:00:00 2001 From: joy Date: Wed, 21 Aug 2024 21:43:37 +0200 Subject: [PATCH] stealling bar --- home/ags/bar/README.md | 15 -- home/ags/bar/applauncher.ts | 107 ----------- home/ags/bar/config.js | 15 -- home/ags/bar/main.ts | 348 ---------------------------------- home/ags/bar/mic.ts | 61 ------ home/ags/bar/notifications.ts | 130 ------------- home/ags/bar/style.css | 40 ---- home/ags/bar/style.scss | 183 ------------------ home/ags/bar/tsconfig.json | 21 -- home/ags/default.nix | 20 +- home/default.nix | 2 +- 11 files changed, 19 insertions(+), 923 deletions(-) delete mode 100644 home/ags/bar/README.md delete mode 100644 home/ags/bar/applauncher.ts delete mode 100644 home/ags/bar/config.js delete mode 100644 home/ags/bar/main.ts delete mode 100644 home/ags/bar/mic.ts delete mode 100644 home/ags/bar/notifications.ts delete mode 100644 home/ags/bar/style.css delete mode 100644 home/ags/bar/style.scss delete mode 100644 home/ags/bar/tsconfig.json diff --git a/home/ags/bar/README.md b/home/ags/bar/README.md deleted file mode 100644 index e311392..0000000 --- a/home/ags/bar/README.md +++ /dev/null @@ -1,15 +0,0 @@ - -# 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: -/nix/store/4rpg1hbvvfb8wpxf1a6ljbm390wfcwcd-ags-1.8.2/share/com.github.Aylur.ags/types diff --git a/home/ags/bar/applauncher.ts b/home/ags/bar/applauncher.ts deleted file mode 100644 index 23dfa40..0000000 --- a/home/ags/bar/applauncher.ts +++ /dev/null @@ -1,107 +0,0 @@ -const { query } = await Service.import("applications") -const WINDOW_NAME = "applauncher" - -/** @param {import('resource:///com/github/Aylur/ags/service/applications.js').Application} app */ -const AppItem = app => Widget.Button({ - on_clicked: () => { - App.closeWindow(WINDOW_NAME) - app.launch() - }, - attribute: { app }, - child: Widget.Box({ - children: [ - Widget.Icon({ - icon: app.icon_name || "", - size: 42, - }), - Widget.Label({ - class_name: "title", - label: app.name, - xalign: 0, - vpack: "center", - truncate: "end", - }), - ], - }), -}) - -const Applauncher = ({ width = 500, height = 500, spacing = 12 }) => { - // list of application buttons - let applications = query("").map(AppItem) - - // container holding the buttons - const list = Widget.Box({ - vertical: true, - children: applications, - spacing, - }) - - // repopulate the box, so the most frequent apps are on top of the list - function repopulate() { - applications = query("").map(AppItem) - list.children = applications - } - - // search entry - const entry = Widget.Entry({ - hexpand: true, - css: `margin-bottom: ${spacing}px;`, - - // to launch the first item on Enter - on_accept: () => { - // make sure we only consider visible (searched for) applications - const results = applications.filter((item) => item.visible); - if (results[0]) { - App.toggleWindow(WINDOW_NAME) - results[0].attribute.app.launch() - } - }, - - // filter out the list - on_change: ({ text }) => applications.forEach(item => { - item.visible = item.attribute.app.match(text ?? "") - }), - }) - - return Widget.Box({ - vertical: true, - css: `margin: ${spacing * 2}px;`, - children: [ - entry, - - // wrap the list in a scrollable - 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 - - // when the applauncher shows up - if (visible) { - repopulate() - entry.text = "" - entry.grab_focus() - } - }), - }) -} - -// there needs to be only one instance -export const applauncher = Widget.Window({ - name: WINDOW_NAME, - setup: self => self.keybind("Escape", () => { - App.closeWindow(WINDOW_NAME) - }), - visible: false, - keymode: "exclusive", - child: Applauncher({ - width: 500, - height: 500, - spacing: 12, - }), -}) diff --git a/home/ags/bar/config.js b/home/ags/bar/config.js deleted file mode 100644 index d8d6444..0000000 --- a/home/ags/bar/config.js +++ /dev/null @@ -1,15 +0,0 @@ -const main = '/tmp/ags/main.js'; - -try { - await Utils.execAsync([ - 'bun', 'build', `${App.configDir}/main.ts`, - '--outfile', main, - '--external', 'resource://*', - '--external', 'gi://*', - '--external', 'file://*', - ]); - await import(`file://${main}`); -} catch (error) { - console.error(error); - App.quit(); -} diff --git a/home/ags/bar/main.ts b/home/ags/bar/main.ts deleted file mode 100644 index 7040972..0000000 --- a/home/ags/bar/main.ts +++ /dev/null @@ -1,348 +0,0 @@ -import micPopup from "mic" -import { applauncher } from "applauncher" -import { NotificationPopups } from "notifications" -// import Gtk from "gi://Gtk?version=3.0" - -const hyprland = await Service.import("hyprland") -const notifications = await Service.import("notifications") -const mpris = await Service.import("mpris") -const audio = await Service.import("audio") -const battery = await Service.import("battery") -const systemtray = await Service.import("systemtray") - -const date = Variable("", { - poll: [5000, `bash -c 'LANG=en_us_8859_1 date "+%H:%M %b %e."'`], -}) -const iconSize = 14; - -function Workspaces() { - const activeId = hyprland.active.workspace.bind("id"); - const workspaces = hyprland.bind("workspaces").as((ws) => - ws - .filter(({ id }) => id > 0) - .sort((a, b) => a.id - b.id) - .map(({ id }) => - Widget.Button({ - on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), - class_name: activeId.as((i) => `${i === id ? "focused" : ""}`), - }) - ) - ); - - return Widget.Box({ - class_name: "workspaces", - children: workspaces, - }); -} - - -function ClientTitle() { - return Widget.Label({ - class_name: "client-title", - label: hyprland.active.client.bind("title"), - }) -} - - -function Clock() { - return Widget.Label({ - class_name: "yellow container", - label: date.bind(), - }) -} - - -// we don't need dunst or any other notification daemon -// because the Notifications module is a notification daemon itself -function Notification() { - const popups = notifications.bind("popups") - return Widget.Box({ - class_name: "notification", - visible: popups.as(p => p.length > 0), - children: [ - Widget.Icon({ - icon: "preferences-system-notifications-symbolic", - size: iconSize, - - className: "icon" - }), - Widget.Label({ - label: popups.as(p => p[0]?.summary || ""), - }), - ], - }) -} - - -function Media() { - const label = Utils.watch("", mpris, "player-changed", () => { - if (mpris.players[0]) { - const { track_artists, track_title } = mpris.players[0] - return `${track_artists.join(", ")} - ${track_title}` - } else { - return "Nothing is playing" - } - }) - - return Widget.Button({ - class_name: "media", - on_primary_click: () => mpris.getPlayer("")?.playPause(), - on_scroll_up: () => mpris.getPlayer("")?.next(), - on_scroll_down: () => mpris.getPlayer("")?.previous(), - child: Widget.Label({ label }), - }) -} - - -function Volume() { - const icons = { - 101: "overamplified", - 67: "high", - 34: "medium", - 1: "low", - 0: "muted", - } - - function getIcon() { - const icon = audio.speaker.is_muted ? 0 : [101, 67, 34, 1, 0].find( - threshold => threshold <= audio.speaker.volume * 100) - - return `audio-volume-${icons[icon!]}-symbolic` - } - - const icon = Widget.Icon({ - icon: Utils.watch(getIcon(), audio.speaker, getIcon), - - size: iconSize, - className: "icon" - }) - - const slider = Widget.Slider({ - hexpand: true, - draw_value: false, - on_change: ({ value }) => audio.speaker.volume = value, - setup: self => self.hook(audio.speaker, () => { - self.value = audio.speaker.volume || 0 - }), - }) - - return Widget.Box({ - class_name: "yellow container", - css: "min-width: 120px", - children: [icon, slider], - }) -} - -function Microphone() { - - function getIcon() { - - if (audio.microphone.is_muted || audio.microphone.volume == 0) { - return "microphone-sensitivity-muted-symbolic" - } else { - return "microphone-sensitivity-high-symbolic"; - } - } - - function getTextStatus() { - if (audio.microphone.is_muted || audio.microphone.volume == 0) { - return "off" - } else { - return "on "; - } - } - - const icon = Widget.Icon({ - icon: Utils.watch(getIcon(), audio.microphone, getIcon), - - className: "icon", - size: iconSize, - }) - - const label = Widget.Label({ - label: Utils.watch(getTextStatus(), audio.microphone, getTextStatus), - }) - - return Widget.Box({ - class_name: "red container", - css: "min-width: 30px", - children: [icon, label], - }) - -} - -function Kblayout() { - - const languages = { - "English": "english", - "Ukrainian": "державна", - "Russian": "русский", - } - - var label = Widget.Label({ - label: "english", - }) - - const icon = Widget.Icon({ - icon: "transporter-symbolic", - - className: "icon", - size: iconSize, - }) - - label.hook(hyprland, (self: any, keyboardname: string, layoutname: string) => { - var maskedName = layoutname; - for (const [key, value] of Object.entries(languages)) { - if (layoutname.includes(key)) - maskedName = value; - } - label.label = maskedName; - }, "keyboard-layout"); - - - return Widget.Box({ - class_name: "orange container", - children: [icon, label], - }) -} - -function Battery() { - const value = battery.bind("percent").as(p => p > 0 ? p / 100 : 0) - // const icon = battery.bind("percent").as(p => - // `battery-${Math.floor(p / 10) * 10}`) - - const icon = battery.bind("percent").as(p => - `battery-full-charging-symbolic`) - - return Widget.Box({ - class_name: "battery container green", - visible: battery.bind("available"), - children: [ - Widget.Icon({ - icon: icon, - icon_size: iconSize, - - className: "icon" - }), - Widget.LevelBar({ - widthRequest: 140, - vpack: "center", - value, - }), - ], - }) -} - - -function SysTray() { - const items = systemtray.bind("items") - .as(items => items.map(item => Widget.Button({ - child: Widget.Icon({ - icon: item.bind("icon"), - size: iconSize, - - className: "icon" - }), - on_primary_click: (_, event) => item.activate(event), - on_secondary_click: (_, event) => item.openMenu(event), - tooltip_markup: item.bind("tooltip_markup"), - }))) - - return Widget.Box({ - children: items, - }) -} - -function NixLogo() { - return Widget.Label({ - label: "", - css: ` - padding-left: 7px; - padding-right: 7px; - color: @blue_1 - `, - }) -} - - -// layout of the bar -function Left() { - return Widget.Box({ - spacing: 8, - children: [ - NixLogo(), - Workspaces(), - // ClientTitle(), - ], - }) -} - -function Center() { - return Widget.Box({ - spacing: 8, - children: [ - Media(), - Notification(), - ], - }) -} - -function Right() { - return Widget.Box({ - hpack: "end", - spacing: 8, - children: [ - Volume(), - Microphone(), - Kblayout(), - Battery(), - // BatteryLabel(), - Clock(), - SysTray(), - ], - }) -} - -function Bar(monitor = 0) { - return Widget.Window({ - name: `bar-${monitor}`, // name has to be unique - class_name: "bar bottombarshadow", - monitor, - anchor: ["top", "left", "right"], - exclusivity: "exclusive", - child: Widget.CenterBox({ - start_widget: Left(), - center_widget: Center(), - end_widget: Right(), - }), - }) -} - -// function Exclusivity(monitor = 0) { -// return Widget.Window({ -// name: `exclusivity-${monitor}`, // name has to be unique -// class_name: "bar bottombarshadow", -// monitor, -// anchor: ["top", "left", "right"], -// exclusivity: "exclusive", -// css: "background-color:transparent;", -// height_request: 35, -// }) -// } - -var bars = hyprland.monitors.map((m, i) => Bar(i)) -// var exclusivity = hyprland.monitors.map((m, i) => Exclusivity(i)) -var micPopups = hyprland.monitors.map((m, i) => micPopup(i)) - -App.config({ - style: "./style.scss", - windows: [ - // ...exclusivity, - ...bars, - ...micPopups, - applauncher, - NotificationPopups() - ], -}) - -export { } diff --git a/home/ags/bar/mic.ts b/home/ags/bar/mic.ts deleted file mode 100644 index cccf6d6..0000000 --- a/home/ags/bar/mic.ts +++ /dev/null @@ -1,61 +0,0 @@ -const audio = await Service.import("audio") - -import Gtk from "gi://Gtk?version=3.0" - -const DELAY = 4000 - -function MicrophoneMute() { - const icon = Widget.Icon({ - class_name: "microphone", - vexpand: true, - hexpand: true, - }) - - const box = Widget.Box({ - child: icon, - class_name: "microphone_box", - }) - - const outside_box = Widget.Box({ - child: box, - css: "margin-bottom:100px;" - }) - - const revealer = Widget.Revealer({ - transition: "slide_up", - child: outside_box, - }) - - let count = 0 - let mute = audio.microphone.stream?.is_muted ?? false - - return revealer.hook(audio.microphone, () => Utils.idle(() => { - if (mute !== audio.microphone.stream?.is_muted) { - mute = audio.microphone.stream!.is_muted - icon.icon = mute ? "microphone-sensitivity-muted-symbolic" : "microphone-sensitivity-high-symbolic" - App.applyCss(mute ? `.microphone_box { color: @red_1; }` : `.microphone_box { color: @green_1; }`) - revealer.reveal_child = true - count++ - - Utils.timeout(DELAY, () => { - count-- - if (count === 0) - revealer.reveal_child = false - }) - } - })) -} - -export default (monitor) => Widget.Window({ - monitor, - name: `indicator${monitor}`, - class_name: "indicator", - layer: "overlay", - anchor: ["bottom"], - click_through: true, - child: Widget.Box({ - css: "padding: 2px;", - expand: true, - child: MicrophoneMute() - }), -}) diff --git a/home/ags/bar/notifications.ts b/home/ags/bar/notifications.ts deleted file mode 100644 index f360d3c..0000000 --- a/home/ags/bar/notifications.ts +++ /dev/null @@ -1,130 +0,0 @@ -const notifications = await Service.import("notifications") - -/** @param {import('resource:///com/github/Aylur/ags/service/notifications.js').Notification} n */ -function NotificationIcon({ app_entry, app_icon, image }) { - 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), - }) -} - -/** @param {import('resource:///com/github/Aylur/ags/service/notifications.js').Notification} n */ -function Notification(n) { - const icon = Widget.Box({ - vpack: "start", - class_name: "icon", - child: NotificationIcon(n), - }) - - const title = Widget.Label({ - class_name: "title", - xalign: 0, - justification: "left", - hexpand: true, - max_width_chars: 24, - truncate: "end", - wrap: true, - label: n.summary, - use_markup: true, - }) - - const body = Widget.Label({ - class_name: "body", - hexpand: true, - use_markup: true, - xalign: 0, - justification: "left", - label: n.body, - wrap: true, - }) - - const actions = Widget.Box({ - class_name: "actions", - children: n.actions.map(({ id, label }) => Widget.Button({ - class_name: "action-button", - on_clicked: () => { - n.invoke(id) - n.dismiss() - }, - hexpand: true, - child: Widget.Label(label), - })), - }) - - return Widget.EventBox( - { - attribute: { id: n.id }, - on_primary_click: n.dismiss, - }, - Widget.Box( - { - class_name: `notification ${n.urgency}`, - vertical: true, - }, - Widget.Box([ - icon, - Widget.Box( - { vertical: true }, - title, - body, - ), - ]), - actions, - ), - ) -} - -export function NotificationPopups(monitor = 0) { - const list = Widget.Box({ - vertical: true, - children: notifications.popups.map(Notification), - }) - - function onNotified(_, /** @type {number} */ id) { - const n = notifications.getNotification(id) - if (n) - list.children = [Notification(n), ...list.children] - } - - function onDismissed(_, /** @type {number} */ id) { - list.children.find(n => n.attribute.id === id)?.destroy() - } - - list.hook(notifications, onNotified, "notified") - .hook(notifications, onDismissed, "dismissed") - - return Widget.Window({ - monitor, - name: `notifications${monitor}`, - class_name: "notification-popups", - anchor: ["top", "right"], - child: Widget.Box({ - css: "min-width: 2px; min-height: 2px;", - class_name: "notifications", - vertical: true, - child: list, - - /** 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/home/ags/bar/style.css b/home/ags/bar/style.css deleted file mode 100644 index abbd3e9..0000000 --- a/home/ags/bar/style.css +++ /dev/null @@ -1,40 +0,0 @@ -window.bar { - background-color: @theme_bg_color; - color: @theme_fg_color; -} - -button { - min-width: 0; - padding-top: 0; - padding-bottom: 0; - background-color: transparent; -} - -button:active { - background-color: @theme_selected_bg_color; -} - -button:hover { - border-bottom: 3px solid @theme_fg_color; -} - -label { - font-weight: bold; -} - -.workspaces button.focused { - border-bottom: 3px solid @theme_selected_bg_color; -} - -.client-title { - color: @theme_selected_bg_color; -} - -.notification { - color: yellow; -} - -levelbar block, -highlight { - min-height: 10px; -} \ No newline at end of file diff --git a/home/ags/bar/style.scss b/home/ags/bar/style.scss deleted file mode 100644 index 34b028d..0000000 --- a/home/ags/bar/style.scss +++ /dev/null @@ -1,183 +0,0 @@ -window.bar { - background-color: @theme_bg_color; - color: @theme_fg_color; - box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.84); -} - -* { - margin: 0px; - padding: 0px; -} - -.magenta { color: @purple_1; } -.magenta highlight { background-color: @purple_1; } - -.yellow { color: @yellow_1; } -.yellow highlight { background-color: @yellow_1; } - -.blue { color: @blue_1; } -.blue highlight {background-color: @blue_1; } - -.red { color: @red_1; } -.red highlight {background-color: @red_1; } - -.green { color: @green_1; } -.green highlight {background-color: @green_1; } - -.magenta { color: @purple_1;} -.magenta highlight {background-color: @purple_1; } - -.orange { color: @orange_1; } -.orange highlight {background-color: @orange_1; } - -button { - min-width: 0; - padding-top: 0; - padding-bottom: 0; - background-color: transparent; -} - -button:active { - background-color: @theme_selected_bg_color; -} - -button:hover { - border-bottom: 3px solid @theme_fg_color; -} - -label { - font-weight: bold; -} - -highlight { - margin: 0px; - padding:0px; -} - -trough { - padding:0px; -} - - -.container { - background-color: lighter(lighter(@theme_bg_color)); - border-radius: 13px; - padding: 0px 10px; - margin-top: 7px; - margin-bottom: 7px; -} - -.container .icon { - padding-right: 10px; -} - -slider { - background-color: transparent; - box-shadow: none; - margin: -100px; -} - -.workspaces { - background-color: lighter(lighter(@theme_bg_color)); - border-radius: 13px; - padding: 3px 10px; - margin: 7px 7px; -} - -.workspaces button { - background-color: @window_fg_color; - min-width: 6px; - min-height: 6px; - padding: 3px 3px; - margin:0px 5px; - border-radius:9999px; -} - -.workspaces button.focused { - background-color: @blue_1; -} - -.client-title { - color: @theme_selected_bg_color; -} - -.notification { - color: yellow; -} - -levelbar block, -highlight { - min-height: 10px; -} - -.microphone_box { - background-color: @theme_bg_color; - min-width: 65px; - min-height: 65px; - margin: 30px; - font-size: 25px; - border-radius: 10px; - box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.84); -} - - -/* Notifications - -window.notification-popups box.notifications { - padding: .5em; -} - -.icon { - min-width: 68px; - min-height: 68px; - margin-right: 1em; -} - -.icon image { - font-size: 58px; - margin: 5px; - color: @theme_fg_color; -} - -.icon box { - min-width: 68px; - min-height: 68px; - border-radius: 7px; -} - -.notification { - min-width: 350px; - border-radius: 11px; - padding: 1em; - margin: .5em; - border: 1px solid @wm_borders_edge; - background-color: @theme_bg_color; -} - -.notification.critical { - border: 1px solid lightcoral; -} - -.title { - color: @theme_fg_color; - font-size: 1.4em; -} - -.body { - color: @theme_unfocused_fg_color; -} - -.actions .action-button { - margin: 0 .4em; - margin-top: .8em; -} - -.actions .action-button:first-child { - margin-left: 0; -} - -.actions .action-button:last-child { - margin-right: 0; -} - -*/ diff --git a/home/ags/bar/tsconfig.json b/home/ags/bar/tsconfig.json deleted file mode 100644 index bdd7690..0000000 --- a/home/ags/bar/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "lib": [ - "ES2022" - ], - "allowJs": true, - "checkJs": true, - "strict": true, - "noImplicitAny": false, - "baseUrl": ".", - "typeRoots": [ - "./types" - ], - "skipLibCheck": true - } - // "include": [ - // "*/*.ts" - // ] -} diff --git a/home/ags/default.nix b/home/ags/default.nix index 3f6fa17..61ace0f 100644 --- a/home/ags/default.nix +++ b/home/ags/default.nix @@ -1,6 +1,22 @@ -{...}: { +{ + pkgs, + inputs, + ... +}: { + imports = [inputs.ags.homeManagerModules.default]; + programs.ags = { enable = true; - configDir = ./bar; + + configDir = ./.; + + extraPackages = with pkgs; [ + bun + ]; }; + + home.packages = with pkgs; [ + bun + ]; + } diff --git a/home/default.nix b/home/default.nix index 42a383b..64bd6cd 100644 --- a/home/default.nix +++ b/home/default.nix @@ -13,6 +13,6 @@ ./hypridle ./neomutt ./newsboat - inputs.ags.homeManagerModules.default + # inputs.ags.homeManagerModules.default ]; }