diff options
| author | eric.marin <maarin.eric@gmail.com> | 2024-12-18 21:06:41 +0100 |
|---|---|---|
| committer | eric.marin <maarin.eric@gmail.com> | 2024-12-18 21:06:41 +0100 |
| commit | 000a7c2a4c4bda36f655f6489b5bac3211515a5d (patch) | |
| tree | 8a5fe85f0632fcca678f0204a4288e6b3423f772 /ags | |
| parent | b0cfdab1e93f660fda8f9398e30c9c996a1760f3 (diff) | |
| download | dotfiles-000a7c2a4c4bda36f655f6489b5bac3211515a5d.tar.gz dotfiles-000a7c2a4c4bda36f655f6489b5bac3211515a5d.zip | |
niri and fuzzel
Diffstat (limited to '')
| -rw-r--r-- | ags/config.js | 41 | ||||
| -rw-r--r-- | ags/modules/applauncher.js | 107 | ||||
| -rw-r--r-- | ags/modules/bar.js | 131 |
3 files changed, 241 insertions, 38 deletions
diff --git a/ags/config.js b/ags/config.js index bc50aa8..cc69e2e 100644 --- a/ags/config.js +++ b/ags/config.js @@ -1,41 +1,6 @@ -// @ts-ignore -const battery = await Service.import("battery") - -const BatteryPercent = () => Widget.Label() - .hook(battery, self => { - self.label = `${battery.percent}%` - self.visible = battery.available - }, "changed") - -const MyButton = () => Widget.Button() - .on("clicked", self => { - print(self, "is clicked") - }) - -const MyDate = () => Widget.Label({ - css: "color:blue; padding: 1em;", -}) - .poll(1000, self => { - self.label = Utils.exec("date +'%_H:%_M:%S'") - }) - -const MyKeybind = () => Widget.Button() - .keybind(["MOD1", "CONTROL"], "a", (_self, _event) => { - print("alt+control+a was pressed") - }) - -const Bar = () => Widget.Window({ - name: 'bar', - anchor: ['top', 'left', 'right'], - child: MyDate(), -}) - -const scss = `${App.configDir}/style.scss` -const css = "/tmp/my-style.css" -Utils.exec(`sassc ${scss} ${css}`) +import { applauncher } from "./modules/applauncher.js" +import { Bar } from "./modules/bar.js" App.config({ - style: css, - windows: [Bar()], + windows: [applauncher, Bar(0)], }) - diff --git a/ags/modules/applauncher.js b/ags/modules/applauncher.js new file mode 100644 index 0000000..f380185 --- /dev/null +++ b/ags/modules/applauncher.js @@ -0,0 +1,107 @@ +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/ags/modules/bar.js b/ags/modules/bar.js new file mode 100644 index 0000000..28fdaee --- /dev/null +++ b/ags/modules/bar.js @@ -0,0 +1,131 @@ +const hyprland = await Service.import("hyprland") +const audio = await Service.import("audio") +const battery = await Service.import("battery") +const network = await Service.import("network") + +const hour = Variable("", { + poll: [60000, 'date "+%H:%M"'] +}) + +function IconLabel(icon, label) { + return [ + Widget.Icon({ icon }), + Widget.Label({ label }), + ] +} + +function Workspaces() { + const active = 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: active.as(i => `${i === id ? "focused" : ""}`) + }))) + return Widget.Box({ + class_name: "workspaces", + children: workspaces, + }) +} + +//function SysTray() { +// +//} + +function Clock() { + return Widget.Label({ + class_name: "clock", + label: hour.bind(), + }) +} + +function Network() { + const label = network.wifi.bind("strength").as(s => ` ${s}`) + return Widget.Box({ + class_name: "network", + children: [ + 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 = Utils.watch(getIcon(), audio.speaker, getIcon) + const label = audio.speaker.bind("volume").as(v => ` ${Math.floor(v * 100 + 0.01)}%`) + + return Widget.Box({ + class_name: "volume", + children: IconLabel(icon, label) + }) +} + +function Battery() { + const label = battery.bind("percent").as(p => ` ${p}%`) + const icon = battery.bind("percent").as(p => + `battery-level-${Math.floor(p / 10) * 10}-symbolic` + ) + + return Widget.Box({ + class_name: "battery", + children: IconLabel(icon, label) + }) +} + +function Left() { + return Widget.Box({ + spacing: 10, + children: [ + Workspaces(), + //SysTray(), + ] + }) +} +function Center() { + return Widget.Box({ + spacing: 10, + children: [ + Clock(), + ] + }) +} +function Right() { + return Widget.Box({ + hpack: "end", + spacing: 10, + children: [ + Network(), + Volume(), + Battery(), + ] + }) +} + +export function Bar(monitor = 0) { + return Widget.Window({ + name: `bar-${monitor}`, + class_name: "bar", + monitor, + anchor: ["top", "left", "right"], + exclusivity: "exclusive", + child: Widget.CenterBox({ + start_widget: Left(), + center_widget: Center(), + end_widget: Right(), + }), + }) +} + |
