launcher ags

This commit is contained in:
wt
2024-09-19 11:09:39 +07:00
parent 09e98c40e8
commit ab13bec186
5 changed files with 146 additions and 0 deletions
+15
View File
@@ -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
+107
View File
@@ -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,
}),
})
+5
View File
@@ -0,0 +1,5 @@
import { applauncher } from "./applauncher.js"
App.config({
windows: [applauncher],
})
+18
View File
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": [
"ES2022"
],
"allowJs": true,
"checkJs": true,
"strict": true,
"noImplicitAny": false,
"baseUrl": ".",
"typeRoots": [
"./types"
],
"skipLibCheck": true
}
}
+1
View File
@@ -0,0 +1 @@
/usr/share/com.github.Aylur.ags/types