From ab13bec18605e7501b46f92040c5a35eaeea4314 Mon Sep 17 00:00:00 2001 From: TolaMironcenko Date: Thu, 19 Sep 2024 11:09:39 +0700 Subject: [PATCH] launcher ags --- ags/launcher/README.md | 15 +++++ ags/launcher/applauncher.js | 107 ++++++++++++++++++++++++++++++++++++ ags/launcher/config.js | 5 ++ ags/launcher/tsconfig.json | 18 ++++++ ags/launcher/types | 1 + 5 files changed, 146 insertions(+) create mode 100644 ags/launcher/README.md create mode 100644 ags/launcher/applauncher.js create mode 100644 ags/launcher/config.js create mode 100644 ags/launcher/tsconfig.json create mode 120000 ags/launcher/types diff --git a/ags/launcher/README.md b/ags/launcher/README.md new file mode 100644 index 0000000..71563ed --- /dev/null +++ b/ags/launcher/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/ags/launcher/applauncher.js b/ags/launcher/applauncher.js new file mode 100644 index 0000000..4b97c7b --- /dev/null +++ b/ags/launcher/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, + }), +}) \ No newline at end of file diff --git a/ags/launcher/config.js b/ags/launcher/config.js new file mode 100644 index 0000000..8c69726 --- /dev/null +++ b/ags/launcher/config.js @@ -0,0 +1,5 @@ +import { applauncher } from "./applauncher.js" + +App.config({ + windows: [applauncher], +}) \ No newline at end of file diff --git a/ags/launcher/tsconfig.json b/ags/launcher/tsconfig.json new file mode 100644 index 0000000..f03f2d1 --- /dev/null +++ b/ags/launcher/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": [ + "ES2022" + ], + "allowJs": true, + "checkJs": true, + "strict": true, + "noImplicitAny": false, + "baseUrl": ".", + "typeRoots": [ + "./types" + ], + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/ags/launcher/types b/ags/launcher/types new file mode 120000 index 0000000..a8e3f04 --- /dev/null +++ b/ags/launcher/types @@ -0,0 +1 @@ +/usr/share/com.github.Aylur.ags/types \ No newline at end of file