diff --git a/home/ags/README.md b/home/ags/README.md deleted file mode 100644 index e311392..0000000 --- a/home/ags/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/applauncher.ts b/home/ags/applauncher.ts deleted file mode 100644 index 23dfa40..0000000 --- a/home/ags/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/main.ts b/home/ags/bar/config.js similarity index 50% rename from home/ags/main.ts rename to home/ags/bar/config.js index 7040972..fd3eb4e 100644 --- a/home/ags/main.ts +++ b/home/ags/bar/config.js @@ -1,8 +1,3 @@ -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") @@ -11,28 +6,26 @@ 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."'`], + poll: [1000, 'date "+%H:%M:%S %b %e."'], }) -const iconSize = 14; + +// widgets can be only assigned as a child in one container +// so to make a reuseable widget, make it a function +// then you can simply instantiate one by calling it 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" : ""}`), - }) - ) - ); + const activeId = hyprland.active.workspace.bind("id") + const workspaces = hyprland.bind("workspaces") + .as(ws => ws.map(({ id }) => Widget.Button({ + on_clicked: () => hyprland.messageAsync(`dispatch workspace ${id}`), + child: Widget.Label(`${id}`), + class_name: activeId.as(i => `${i === id ? "focused" : ""}`), + }))) return Widget.Box({ class_name: "workspaces", children: workspaces, - }); + }) } @@ -46,7 +39,7 @@ function ClientTitle() { function Clock() { return Widget.Label({ - class_name: "yellow container", + class_name: "clock", label: date.bind(), }) } @@ -62,9 +55,6 @@ function Notification() { children: [ Widget.Icon({ icon: "preferences-system-notifications-symbolic", - size: iconSize, - - className: "icon" }), Widget.Label({ label: popups.as(p => p[0]?.summary || ""), @@ -107,14 +97,11 @@ function Volume() { 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` + 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({ @@ -127,103 +114,23 @@ function Volume() { }) return Widget.Box({ - class_name: "yellow container", - css: "min-width: 120px", + class_name: "volume", + css: "min-width: 180px", 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() { +function BatteryLabel() { 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`) + `battery-level-${Math.floor(p / 10) * 10}-symbolic`) return Widget.Box({ - class_name: "battery container green", + class_name: "battery", visible: battery.bind("available"), children: [ - Widget.Icon({ - icon: icon, - icon_size: iconSize, - - className: "icon" - }), + Widget.Icon({ icon }), Widget.LevelBar({ widthRequest: 140, vpack: "center", @@ -237,12 +144,7 @@ function Battery() { 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" - }), + 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"), @@ -253,26 +155,14 @@ function SysTray() { }) } -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(), + ClientTitle(), ], }) } @@ -293,10 +183,7 @@ function Right() { spacing: 8, children: [ Volume(), - Microphone(), - Kblayout(), - Battery(), - // BatteryLabel(), + BatteryLabel(), Clock(), SysTray(), ], @@ -306,7 +193,7 @@ function Right() { function Bar(monitor = 0) { return Widget.Window({ name: `bar-${monitor}`, // name has to be unique - class_name: "bar bottombarshadow", + class_name: "bar", monitor, anchor: ["top", "left", "right"], exclusivity: "exclusive", @@ -318,31 +205,16 @@ function Bar(monitor = 0) { }) } -// 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", + style: "./style.css", windows: [ - // ...exclusivity, - ...bars, - ...micPopups, - applauncher, - NotificationPopups() + Bar(), + + // you can call it, for each monitor + // Bar(0), + // Bar(1) ], }) export { } + diff --git a/home/ags/bar/style.css b/home/ags/bar/style.css new file mode 100644 index 0000000..29f8fdd --- /dev/null +++ b/home/ags/bar/style.css @@ -0,0 +1,40 @@ +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; +} diff --git a/home/ags/config.js b/home/ags/config.js deleted file mode 100644 index d8d6444..0000000 --- a/home/ags/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/default.nix b/home/ags/default.nix index 61ace0f..e43fd97 100644 --- a/home/ags/default.nix +++ b/home/ags/default.nix @@ -1,22 +1,8 @@ -{ - pkgs, - inputs, - ... -}: { +{inputs,...}: { imports = [inputs.ags.homeManagerModules.default]; - programs.ags = { enable = true; - - configDir = ./.; - - extraPackages = with pkgs; [ - bun - ]; + configDir = ./bar; }; - - home.packages = with pkgs; [ - bun - ]; - } + diff --git a/home/ags/mic.ts b/home/ags/mic.ts deleted file mode 100644 index cccf6d6..0000000 --- a/home/ags/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/nixos-switch.log b/home/ags/nixos-switch.log new file mode 100644 index 0000000..9fec16a --- /dev/null +++ b/home/ags/nixos-switch.log @@ -0,0 +1,3 @@ +warning: Git tree '/home/joy/nix' is dirty +building the system configuration... +warning: Git tree '/home/joy/nix' is dirty diff --git a/home/ags/notifications.ts b/home/ags/notifications.ts deleted file mode 100644 index f360d3c..0000000 --- a/home/ags/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/style.scss b/home/ags/style.scss deleted file mode 100644 index 34b028d..0000000 --- a/home/ags/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/tsconfig.json b/home/ags/tsconfig.json deleted file mode 100644 index bdd7690..0000000 --- a/home/ags/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" - // ] -}